bind函数polyfill源码解析
準(zhǔn)備知識
使用new來調(diào)用函數(shù)會自動執(zhí)行下面的操作:
注意this綁定規(guī)則,new操作具有最高的優(yōu)先級
《你不知道的JavaScript(上卷)》提供了一個例子,bar被硬綁定到obj上,但是new bar(3) 并沒有像我們預(yù)計的那樣把obj.a修改為3。相反,new修改了硬綁定調(diào)用bar()中的this。因為使用了new綁定,我們得到了一個名字為baz的新對象,并且baz.a的值為3。
function foo(something) {this.a = something } var obj = {} var bar = foo.bind(obj) bar(2) console.log(obj.a) //2 var baz = new bar(3) console.log(obj.a) //2 console.log(baz.a) //3instanceof運算符的第一個變量是一個對象,暫時稱為A;第二個變量一般是一個函數(shù),暫時稱為B。
instanceof判斷準(zhǔn)則:沿著A的__proto__這條線來找,同時沿著B的prototype這條線來找,如果兩條線能找到同一個引用,即同一個對象,那么就返回true。
源碼分析
MDN上提供的polyfill如下,主要的疑惑點應(yīng)該就是 this instanceof fNOP 作用是什么?
if (!Function.prototype.bind) {Function.prototype.bind = function(oThis) {if (typeof this !== '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 // 這段代碼會判斷硬綁定函數(shù)是否是被new調(diào)用,如果是的話就會使用新創(chuàng)建的this替換硬綁定的this? this: oThis,aArgs.concat(Array.prototype.slice.call(arguments)))}// 維護(hù)原型關(guān)系if (this.prototype) {// Function.prototype doesn't have a prototype propertyfNOP.prototype = this.prototype; }fBound.prototype = new fNOP()return fBound} }this instanceof fNOP 單獨看是看不明白的,需要結(jié)合以下代碼才能說明它的作用
if (this.prototype) {fNOP.prototype = this.prototype; } fBound.prototype = new fNOP()首先我們要清楚:bind(...)會返回一個硬編碼的新函數(shù),它會把參數(shù)設(shè)置為this的上下文并調(diào)用原始函數(shù)。
重點就是bind(...)返回的是一個函數(shù)!函數(shù)!函數(shù)!這意味著可以對bind(...)返回的函數(shù)進(jìn)行new操作,那么問題就來了。
this綁定中new操作具有最高的優(yōu)先級,如果執(zhí)行new操作,bind(...)應(yīng)該不起作用,this應(yīng)該指向new出來的新對象。
清楚了以上內(nèi)容,我們開始閱讀代碼。
if (typeof this !== 'function') {throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable')}bind(...)必須由函數(shù)調(diào)用,所以以上代碼對this的類型進(jìn)行檢查,如果不是函數(shù)類型則拋出錯誤。
var aArgs = Array.prototype.slice.call(arguments, 1) var fToBind = this var fBound = function() {return fToBind.apply(this instanceof fNOP // 這段代碼會判斷硬綁定函數(shù)是否是被new調(diào)用,如果是的話就會使用新創(chuàng)建的this替換硬綁定的this? this: oThis,aArgs.concat(Array.prototype.slice.call(arguments)))}aArgs獲取傳入的其它參數(shù),fToBind獲取需要硬綁定的函數(shù),fBound為返回的綁定操作函數(shù),我們先忽略fBound里面的內(nèi)容,繼續(xù)往下看。
if (this.prototype) {fNOP.prototype = this.prototype; } fBound.prototype = new fNOP()我們假設(shè)對bind(...)返回的函數(shù)進(jìn)行new操作(原型鏈如下),則this instanceof fNOP 為true,此時我們就知道執(zhí)行了new操作,硬綁定的this不能生效,需要把this綁定到新生成的對象上。
如果沒有進(jìn)行new操作的話,就用apply模擬bind綁定,一切按照原計劃進(jìn)行。
最后我們分析一下維護(hù)原型關(guān)系的重要性,例子如下:
function Foo(){console.log(this.a);this.a=1; } Foo.prototype.show=function() {console.log(this.a)}; Foo(); // undefined var obj1=new Foo(); obj1.show();var bar=Foo.bind({a:2}); bar(); // 2 var obj2=new bar(); obj2.show();因為bind函數(shù)內(nèi)部保持了原型關(guān)系的繼承,所以對象obj2才能訪問到原型上的show方法。
** 注意:Foo.show()是錯誤的,因為Foo的原型指向的是Function.prototype,只有Foo的實例才能調(diào)用show方法。
更多專業(yè)前端知識,請上 【猿2048】www.mk2048.com
總結(jié)
以上是生活随笔為你收集整理的bind函数polyfill源码解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅谈一下我了解的PWA
- 下一篇: 面试常见问题之实现bind函数