Skip to content

call方法内部执行时: 让func函数立即执行,func函数中的this为第一个参数,之后的参数当作实参传递给func函数

apply方法内部执行时: 让func函数立即执行,func函数中的this为第一个参数,第二个参数(数组)当作实参一项项传递给func函数

bind方法内部执行时: func不立即执行, 把传递进来的信息存储起来(闭包) bind执行完返回一个新的函数,把新函数绑定给元素的事件,当事件触发时执行的是新函数 执行新函数时内部调用func, 并修改this和传入参数

js
~(function (proto) {
  const isPrimitive = function isPrimitive (target) {
    return target == null || !/^(function|object)$/.test(typeof target)
  }

  const call = function call (context, ...args) {
    if (isPrimitive(context)) {
      context = context == null
        ? window
        : new Object(context)
    }

    const key = Symbol('key')
    const fn = this
    context[key] = fn

    const result = context[key](...args)
    delete context[key]

    return result
  }  

  const apply = function apply (context, args) {
    if (isPrimitive(context)) {
      context = context == null
        ? window
        : new Object(context)
    }

    if (isPrimitive(args)) {
      if (args == null) {
        args = []
      } else {
        throw new Error('invalid args')
      }
    } else if (!Array.isArray(args)) {
      args = []
    }

    const key = Symbol('key')
    const fn = this
    context[key] = fn

    const result = context[key](...args)
    delete context[key]

    return result
  }

  const bind = function bind (context, ...args1) {
    const fn = this
    return function proxy (...args2) {
      fn.call(context, ...args1, ...args2)
      // fn.apply(context, args1.concat(args2))
    }
  }

  proto.call = call
  proto.apply = apply
  proto.bind = bind
})(Function.prototype)
js
function fn () {
  console.log(this)
}
// 非严格模式下,不传/undefined/null,this -> window,传其他值 this -> 其他值
// 严格模式下,不传/undefined,this -> undefined,传谁this就是谁,传null,this -> null
fn.call() // this -> window
fn.call(null) // this -> window

// example1
function fn1 () {
  console.log(1)
}
function fn2 () {
  console.log(2)
}
fn1.call(fn2) 
// fn1.call() context -> fn2, this -> fn1, context[key] = this, context[key]() => this(), 只不过函数里的this是fn2
// fn1(), 输出1
fn1.call.call(fn2) 
// fn1.call.call(fn2) context -> fn2, this -> fn1.call, context[key] = this, context[key]() => this(), 只不过函数里面this是fn2
// fn1.call() context -> window, this => fn2(上一步确定下来的), context[key] = this, context[key]() => this(), 只不过函数里的this是fn2
// fn2(), 输出2
Function.prototype.call(fn1)
// Function.prototype.call(fn1) context -> fn1, this -> Function.prototype, context[key] = this,  context[key]() => this(), 只不过函数里面的this是fn1
// Function.prototype(), 没有任何输出
Function.prototype.call.call(fn1)
// Function.prototype.call.call(fn1) context -> fn1, this -> Function.prototype.call, context[key] = this, context[key]() => this(), 只不过函数里的this是fn1
// Function.prototype.call() context -> window, this -> fn1, context[key] = fn1, context[key]() => this(), 只不过函数里的this是window
// fn1(), 输出1
// 结论
// 一个call,让call左边的函数执行
// 两个及以上call,让最后一个call的第一个参数执行

// 通过apply求数组最大/最小值, this是谁无所谓
const arr = [1, 2, 3]
Math.max.apply(Math, arr) // 3

// 通过apply合并数组
const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
Array.prototype.push.apply(arr1, arr2) // [ 1, 2, 3, 4, 5, 6 ]
// arr1.push.apply(arr1, arr2)
// [].push.apply(arr1, arr2)

// babel
let min = Math.min(...arr) // => var min = Math.min.apply(Math, _toConsumableArray(arr))