bind(..) polyfill 代码与内置函数bind的区别

之前写了关于bind(..) polyfill 代码的理解,记录了自己的你不知道的JavaScript(上卷)93页提及的bind() polyfill 代码的一些理解,书中提到

由于 polyfill 并不是内置函数, 所以无法创建一个不包含 .prototype的函数, 因此会具有一些副作用。

关于这一点,我是不明所以的。而在阅读到书中的156页时才发现了二者的一些区别:

  1. 内置函数没有 .prototype 属性的。 在这样的函数上使用 instanceof 的话,目标函数的 .prototype 会代替硬绑定函数的 .prototype。而自定义的bind()是有 .prototype
  2. 利用new创建使用了硬绑定(bind)的函数时,虽然不管是内置函数还是polyfill 代码,其构造的对象均指向硬绑定(bind)的函数的点prototype,但是new 的函数是不一样的,使用内置函数相当于new的是目标函数,而polyfill 代码new的是fBound对象。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <script>
    // 强制使用自定义的bind
    // 通过注释或者不注释这段代码可以看到使用内置函数和自定义的bind的区别
    // 本来这一句是if (!Function.prototype.bind) { ,在浏览器不兼容bind时添加自定义的bind方法,为了测试,强制浏览器使用自定义的bind
    if (true) { 
      Function.prototype.bind = function(oThis) { // oThis在本例中就是obj
        // 做的事:判断调用bind方法的对象是不是一个函数function,若不是则报错
        // 也就是说此方法只能是函数调用吗?这部分没太理解为什么要这样做
        if (typeof this !== "function") { 
          // 与 ECMAScript 5 最接近的 
          // 内部 IsCallable 函数 
          throw new TypeError( "Function.prototype.bind - what is trying " + "to be bound is not callable" ); 
        } 
        // Array.prototype.slice.call将类数组转换为数组,同时剔除了传入的第一个参数,即对象,而如果除了对象,还传入了其他参数,则参数会保留
        // 把除了第一个参数(第一个参数用于绑定 this) 之外的其他参数都传给下层的函数(这种技术称为“部分应用”, 是“柯里化” 的一种)
        var aArgs = Array.prototype.slice.call( arguments, 1 ), 
        fToBind = this, // 本例中this就是foo
        fNOP = function(){}, 
        fBound = function(){ 
            debugger;

          return fToBind.apply(
            // 如果this的原型链上有fNOP并且oThis转换为布尔值是true才用本来指向的this,否则将它转成oThis
            // 这里就是判断是否要修改绑定的对象了
            // 这里我的理解是如果this instanceof fNOP并且oThis是undefined或null等,就认为开发者是特意这样设置的,按照开发者的意愿绑定对象,
            // 但是this instanceof fNOP 这句又是什么意思呢
            // this 的原型链上有fNOP的原型才会是true,什么情况下它会是true呢?
            // 我认为这里是为了保持绑定的优先级(p94页)
            // 优先级: new > 显示绑定 > 隐式绑定 > 默认绑定
            // 原文说:这段代码会判断硬绑定函数是否是被 new 调用, 如果是的话就会使用新创建的 this 替换硬绑定的 this。
            // 回忆一下,fBound的原型是fNOP构造的对象,那么当fBound作为构造函数,也就是说new调用时this指向的就是fNOP构造的对象,此时this 的原型链上有fNOP的原型,此时会返回true
            // 也就是说这句话的意思是开发者用了new调用同时开发者传入的显示绑定对象不是null或者undefined这种值时,使用新创建的 this
            // 否则显式调用都会生效
            (this instanceof fNOP && oThis ? this : oThis ), 
            // 将之前的参数和新传入的参数拼接起来
            aArgs.concat( Array.prototype.slice.call( arguments ) )
          ); 
        }; 
        fNOP.prototype = this.prototype; 
        fBound.prototype = new fNOP(); 
        return fBound; 
      }; 
    };
    function Person(name){
      this.name = name;
    }
    var obj = {name:"obj的name"};
    var tmp = Person.bind(obj);
    var one = new Person('one');

    console.log( one instanceof tmp); // 使用自定义的bind返回false,原生是true,因为内置函数没有 .prototype 属性的。 在这样的函数上使用 instanceof 的话,目标函数的 .prototype 会代替硬绑定函数的 .prototype。

    // 另外,
    var two = new tmp('two');
    console.log(two); // 内置:Person {name: "two"} 自定义:fBound {name: "two"}
    console.log(two instanceof tmp) // 内置的返回true 自定义:true
  </script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值