bind兼容性代码理解

关于bind的兼容性处理,书中列出了如下代码:

if (!Function.prototype.bind) {
      Function.prototype.bind = function (oThis) {
        if (typeof this !== 'function') {
          // 与 ECMAScript 5 最接近的
          // 内部 IsCallable 函数
          throw new TypeError(
            'Function.prototype.bind - what is trying ' +
              'to be bound is not callable'
          );
        }
        var aArgs = Array.prototype.slice.call(arguments, 1),
          fToBind = this,
          fNOP = function () {},
          fBound = function () {
            return fToBind.apply(
              this instanceof fNOP && oThis ? this : oThis,
              aArgs.concat(Array.prototype.slice.call(arguments))
            );
          };
        fNOP.prototype = this.prototype;
        fBound.prototype = new fNOP();
        return fBound;
      };
    }

代码的方法都认识,为什么组合到一起就搞不清是什么意思了呢?

我们先来看看MDN中对bind方法的解释:

Function实例的 bind() 方法创建一个新函数,当调用该新函数时,它会调用原始函数并将其 this 关键字设置为给定的值,同时,还可以传入一系列指定的参数,这些参数会插入到调用新函数时传入的参数的前面。

具体解释清参考MDN:Function.prototype.bind() - JavaScript | MDN

既然看不明白,那就打断点来看看吧:

首先,这里面的this很好理解,指向的是调用bind方法的方法,比如a.bind(b),指向的为a

让我迷惑的地方出现了

fBound = function () {
          return fToBind.apply(
            this instanceof fNOP && oThis ? this : oThis,
            aArgs.concat(Array.prototype.slice.call(arguments))
          );
        };

起初不能理解,this instanceof fNOP && oThis ? this : oThis 这段三元运算是在干什么,后来通过资料了解(上文分享的MDN网址),在使用构造方法也就是new操作符去调用bind时,需要忽略this硬性绑定,也就是说指定的this无效,那再来看这段代码,如果this(注意,这里的this,不是上文例子中的a或者b,而是全局对象windows,请继续看下面例子)是fNOP的实例(通过new调用)并且有oThis(传进来需要绑定this的方法)时,apply绑定的this为windows,否则apply绑定bind传入的方法。

解决了一个语句,终于可以继续了,但是,下面这个语句简直是在迷惑人!

var aArgs = Array.prototype.slice.call(arguments, 1);
aArgs.concat(Array.prototype.slice.call(arguments))

什么?这是什么神操作呢,这两句代码如果单独运行是这样的

 var arguments = ['this', 1, 2, 3];
    var aArgs = Array.prototype.slice.call(arguments, 1); // 1,2,3
    console.log('aArgs =', aArgs);
    var bArgs = aArgs.concat(Array.prototype.slice.call(arguments)); // 1,2,3,'this',1,2,3
    console.log('bArgs =', bArgs);

我的本能告诉我,这不对,肯定哪里有问题,我又想到,不能脱离环境而单独运行代码,这次我在调用的地方打断点,准备搞懂为什么要这样写

Function.prototype.bind = function (oThis) {
      if (typeof this !== 'function') {
        // 与 ECMAScript 5 最接近的
        // 内部 IsCallable 函数
        throw new TypeError(
          'Function.prototype.bind - what is trying ' +
            'to be bound is not callable'
        );
      }
      console.log('this1 =', this);
      console.log('arguments1 =', arguments);
      var aArgs = Array.prototype.slice.call(arguments, 1);
      var fToBind = this,
        fNOP = function () {},
        fBound = function () {
          console.log('arguments2 =', arguments);
          console.log('this2 =', this);
          return fToBind.apply(
            this instanceof fNOP && oThis ? this : oThis,
            aArgs.concat(Array.prototype.slice.call(arguments))
          );
        };
      fNOP.prototype = this.prototype;
      fBound.prototype = new fNOP();
      return fBound;
    };

    const module = {
      x: 88,
      getX: function (...data) {
        console.log('data =', data);
        return this.x;
      },
    };
    const unboundGetX = module.getX;
    const boundGetX = unboundGetX.bind(module, 1, 2, 3);
    console.log(boundGetX('a', 'b'));

豁然开朗!代码中的两个arguments不一样,aArgs.concat(Array.prototype.slice.call(arguments))执行之后,是将两次传入的参数拼接在了一起,也就是代码中第一次传参为module, 1, 2, 3,第二次为'a', 'b',拼接之后为1, 2, 3, 'a', 'b' 又去查了下资料,这种将多入传参变为单入传参的方法叫函数柯里化。

到此我的疑惑基本都解决了,bind兼容性核心功能也搞明白了,最后两段代码模拟了Object.creat方法

fNOP = function () {},
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();

参考文章:Function.prototype.bind · javascript中的polyfill

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值