美文网首页程序员
为什么连续bind只有第一次的绑定值生效

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

作者: Eileen_1d88 | 来源:发表于2019-10-10 07:27 被阅读0次

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

    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只有第一次的绑定值生效

        本文链接:https://www.haomeiwen.com/subject/kcrnpctx.html