實現bind函數
參考MDN提供的Polyfill方案
Function.prototype.myBind = function(context){ //這里對調用者做一個判斷,如果不是函數類型,直接拋異常 if(typeof this !== 'function'){ throw '調用必須為函數' } //當我們調用bind函數時,我們可能傳了不只一個參數 //如 fun.bind({}, arg1, arg2) //我們需要把后面的參數拿出來 let args = Array.prototype.slice.call(arguments, 1); let fToBind = this; let fNOP = function(){}; let fBound = function(){ return fToBind.apply(this instanceof fNOP ? this : context, args.concat(arguments)); } if(this.prototype){ fNOP.prototype = this.prototype; } fBound.prototype = new fNOP(); return fBound; }
fBound函數這里有個判斷 this instanceof FNOP 這個其實是為了避免一種情況,因為bind函數返回的是一個函數,當我們把這個函數實例化(就是new fun())
根據官方文檔 當返回的函數被實例化的時候,this指向會鎖定指向該實例,不管我們傳入的參數指定this指向。
在下面我們 返回的fBound函數時 繼承一個空函數 FNOP, 當返回的函數被實例化之后,this instanceof fNOP 結果為true,從而指定this指向
function a (){} function b (){} a.prototype = new b(); //如果我們返回的函數實例化了 let c = new a(); c instanceof b //true //但是大多數情況我們都是 a instanceof b // false
如果這里明白了,那后面的就簡單了,context 參數就是我們手動指定的this指向, 當我們綁定bind時會傳遞多個參數,執行的時候也會帶參數,我們就需要把bind
函數除掉第一個以外的參數和我們調用方式時的參數進行拼接
function foo (){} //示例中 args 就是指的[arg1, arg2] //args.concat(arguments) 就是將所有的arg1,arg2...arg4的參數進行拼接 let newFoo = foo.bind({}, arg1, arg2); newFoo(arg3, arg4);
另外 arguments 參數不要搞混淆了,上面那個獲取的是bind時的參數(就是{}, arg1, arg2)
下面的arguments 參數是指的調用時的 (就是 arg3, arg4)