bind、apply、call - freddielovekqy/dung-beetle GitHub Wiki

apply与call的底层实现原理,都是讲方法本身赋值给传递的新的this对象,作为新的this对象的一个属性,执行this对象的这个方法,来重定向方法内的this值。 apply与call除了方法参数的设置方式外,在原理上也没有任何区别。

Function.prototype.newCall = function (content, ...args) {
  content = content || window;
  content.fn = this;
  const result = content.fn(...args);
  delete content.fn;
  return result;
}

Function.prototype.newApply = function (content, args) {
  content = content || window;
  content.fn = this;
  const result = content.fn(...args);
  delete content.fn;
  return result;
}

bind底层原理实现与上面两种方式不同,但是底层也是通过call或者apply与闭包来实现的。bind返回一个新的方法对象。

Function.prototype.myBind = function (context, ...bindArgs) {
  if (typeof this !== 'function') {
    throw new TypeError('this is not a function');
  }
  const _this = this;
  return function Fn(...execArgs) {
    const args = bindArgs.concat(execArgs);
    return _this.call(this instanceof Fn ? this : context, ...args);
  }
}

注意bind无法连续两次使用修改一个方法内的this指向,多次使用,this指向总是指向第一次调用时传入的值。

原因是:bind返回的新的方法中,包含闭包,第二次使用bind的时候,return后的_this实际上是前一个bind新返回的Fn方法,Fn方法在执行时,方法内的_this指向老的方法,this值为window,所以.call执行时传入的内容是第一次调用bind时候产生的context值,即第一次调用bind时候传入的this指向。