Javascript中从学习bind到实现bind的过程(2)

通过上面代码可以看出,that始终指向bar。同时返回的函数已经继承了that.prototype即bar.prototype。为什么不直接让返回的函数的prototype属性resultFunc.prototype 等于为bar(that).prototype呢,这是因为任何new出来的实例都可以访问原型链。如果直接赋值那么new出来的对象可以直接修改bar函数的原型链,这也就是是原型链污染。所以我们采用继承的方式(将构造函数的原型链赋值为父级构造函数的实例),让new出来的对象的原型链与bar脱离关系。

2.判断当前被调用时,this是用于普通的bind还是用于构造函数从而更改this指向。

如何判断当前this指向了哪里呢,通过第一点我们已经知道,通过bind方法返回的新函数已经有了原型链,剩下需要我们做的就是改变this的指向就可以模拟完成了。通过什么来判断当前被调用是以何种姿势呢。答案是instanceof 。

instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。

// 定义构造函数 function C(){} function D(){} var o = new C(); // true,因为 Object.getPrototypeOf(o) === C.prototype o instanceof C; // false,因为 D.prototype不在o的原型链上 o instanceof D;

从上面可以看出,instanceof可以判断出一个对象是否是由这个函数new出来的,如果是new出来的,那么这个对象的原型链应为该函数的prototype.

所以我们来看这段关键的返回的函数结构:

var resultFunc = function() { return that.apply(this instanceof that ? this : newThis, aArgs.concat(Array.prototype.slice.call(arguments))) }

在这其中我们要先认清this instanceof that 中的this是bind函数被调用后,返回的新函数中的this。所以这个this可能执行在普通的作用域环境,同时也可能被new一下从而改变自己的指向。再看that,that始终指向了bar,同时其原型链that.prototype是一直存在的。所以如果现在这个新函数要做new操作,那么this指向了新函数,那么 this instanceof that === true, 所以在apply中传入this为指向,即指向新函数。如果是普通调用,那么this不是被new出来的,即新函数不是作为构造函数,this instanceof that === false就很显而易见了。这个时候是正常的bind调用。将调用的第一个参数作为this的指向即可。

完整代码(MDN下的实现)

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'); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function() {}, fBound = function() { return fToBind.apply(this instanceof fNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); }; if (this.prototype) { // Function.prototype doesn't have a prototype property fNOP.prototype = this.prototype; } fBound.prototype = new fNOP(); return fBound; }; }

可以看到,其首先做了当前是否支持bind的判定,不支持再实行兼容。同时判断调用这个方法的对象是否是个函数,如果不是则报错。

同时这个模拟的方法也有一些缺陷,可关注MDN上的Polyfill部分

小结

模拟bind实现最大的一个缺陷是,模拟出来的函数中会一直存在prototype属性,但是原生的bind作为构造函数是没有prototype的,这点打印一下即可知。不过这样子new出来的实例没有原型链,那么它的意义是什么呢。

大家在学习的时候如果还有任何问题,可以在下面的留言区讨论,感谢你的支持。

您可能感兴趣的文章:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/wyyzjz.html