为什么连续bind只有第一次的绑定值生效

今天面试今日头条,被问到这样一段代码

function func(...args) {
        console.log(this, ...args)
}
func.bind({a:1}).bind({b: 1})(2,3)

结果是:

{a: 1} 2 3

为什么呢?MDN中给出的Polyfill是这样的, 虽然和标准实现有些差别,但基本的功能是一样的,我们可以用它来了解bind的实现原理:

if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) {
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }
    // 有朋友表示不知道这里为什么这样写,其实原因是
    // arguments是一个类数组,它本身看起来像一个数组,但是它不没有数组的方法
    // 那么这里我们要取出arguments里第一个参数往后的参数的话,就需要给这个arguments赋予一个slice方法
    // Array.prototype.slice.call(arguments)就是当slice执行时,this指向了arguments,
    // 就相当于arguments.slice()
    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
            console.log('this', this);
            console.log('oThis', oThis);
          // this instanceof fBound === true时,说明返回的fBound被当做new的构造函数调用
          return fToBind.apply(this instanceof fBound
                 ? this
                 : oThis,
                 // 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    // 维护原型关系
    if (this.prototype) {
      // 当执行Function.prototype.bind()时, this为Function.prototype 
      // this.prototype(即Function.prototype.prototype)为undefined
      fNOP.prototype = this.prototype; 
    }
    // 下行的代码使fBound.prototype是fNOP的实例,因此
    // 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
    fBound.prototype = new fNOP();
    return fBound;
  };
}

执行

function test(...args) {
  console.log(this, ...args);
}
test.bind({a:1}).bind({b: 1})(2,3);

可以看到控制台的打印:


image.png

根据这个打印结果以及bind的实现,我们可以看到,bind的实现方式是一个柯里化的函数,每次的绑定就相当于:

function test(...args) {
  console.log(this, ...args);
}
function f1() {
  return test.apply({a: 1})
}
function f2() {
  return f1.apply({b: 1})
}
f2()

把f1换成第一次bind,f2换成第二次bind,就可以明白为什么最后只有第一个bind生效,因为执行到最后时,传进去的oThis就是第一次绑定的对象。
ps:关于函数的柯里化如何实现,我还没有太理解,希望下次能明白

你可能感兴趣的:(为什么连续bind只有第一次的绑定值生效)