learn icon indicating copy to clipboard operation
learn copied to clipboard

JavaScript深入之bind的模拟实现

Open yangtao2o opened this issue 4 years ago • 0 comments

JavaScript深入之bind的模拟实现

基本实现

我们可以首先得出 bind 函数的两个特点:

  • 返回一个函数
  • 可以传入参数

如:

var foo = {
  value: 1
};

function bar(name, age) {
  console.log(this.value);
  console.log(name);
  console.log(age);
}

var bindFoo = bar.bind(foo, "yyy");
bindFoo("28");

第一步:返回一个函数

Function.prototype.mybind1 = function(context) {
  const self = this;
  return function() {
    return self.apply(context);
  };
};

第二步:可以传参,并且可以这样:函数需要传 name 和 age 两个参数,可以在 bind 的时候,只传一个 name,在执行返回的函数的时候,再传另一个参数 age!

Function.prototype.mybind2 = function(context) {
  const self = this;
  const args = Array.prototype.slice.call(arguments, 1);
  return function() {
    const bindArgs = Array.prototype.slice.call(arguments);
    return self.apply(context, args.concat(bindArgs));
  };
};

构造函数效果实现

完成了这两点,最难的部分到啦!因为 bind 还有一个特点,就是

一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。

第三步

Function.prototype.mybind3 = function(context) {
  const self = this;
  const args = Array.prototype.slice.call(arguments, 1);
  // 通过一个空函数来进行中转
  const fNOP = function() {};
  const fBound = function() {
    const bindArgs = Array.prototype.slice.call(arguments);
    // this 指向 实例,说明是构造函数,需要将绑定函数的 this 指向该实例,
    // 可以让实例获得来自绑定函数的值
    // this 指向 window,说明使普通函数调用,将绑定函数的 this 指向 context
    return self.apply(
      this instanceof fNOP ? this : context,
      args.concat(bindArgs)
    );
  };
  fNOP.prototype = this.prototype;
  // 让实例继承绑定函数的原型(this.prototype)中的值
  fBound.prototype = new fNOP();
  return fBound;
};

最终版

Function.prototype.mybind = function(context) {
  if (typeof this !== "function") {
    throw new Error(
      "Function.prototype.bind - what is trying to be bound is not callable"
    );
  }
  const self = this;
  const args = Array.prototype.slice.call(arguments, 1);
  const fNOP = function() {};

  const fBound = function() {
    const bindArgs = Array.prototype.slice.call(arguments);
    return self.apply(
      this instanceof fNOP ? this : context,
      args.concat(bindArgs)
    );
  };

  fNOP.prototype = this.prototype;
  fBound.prototype = new fNOP();
  return fBound;
};

学习资料:JavaScript深入之bind的模拟实现

yangtao2o avatar Mar 29 '20 07:03 yangtao2o