if(!Function.prototype.bind){
Function.prototype.bind = function(oThis){
if(typeof this !=="function"){ //如果不函數拋出異常
throw new TyperError("")
}
var aArgs = Array.prototype.slice.call(arguments,1), //此處的aArgs是除函數外的參數
fToBind = this, //要綁定的對象
fNOP = function(){},
fBound = function(){
return fToBind.apply(
this instanceof fNOP ? this:oThis||this,aArgs.concat(Array.prototype.slice.call(arguments)));
)
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
}
}
明白 bind 的用法就必須要知道 apply 的用法,MDN 指出,apply 是直接修改了函數內部的指向到第一個參數,並將第二個參數數組傳參進函數並運行這個函數。也就是說
var obj = {test: function() { console.log(this, arguments) }}, func = obj.test; obj.test("Hello", ",", "world", "!"); func.apply(obj, ["Hello", ",", "world", "!"]);
這兩種運行方式是一樣的。那么回到 Polyfill 中發現參數的寫法是 args.concat(slice.call(arguments))。args 是將 bind時候定義的除第一個參數外的其它參數,而此時的 arguments 是指函數調用時候的參數,通過數組的操作將這兩個參數合並成一個數組傳入函數內部。看個例子你可能更容易明白:
/** 代碼接上 **/ var newFunc = func.bind(obj, "Hello", ","); newFunc("world", "!");
那么再來回答問題一,這個是典型的屬性繼承的方法,本來使用
bound.prototype = self.prototype
就可以將原屬性集成過來了,但是這樣兩個對象屬性都指向同一個地方,修改 bound.prototype 將會造成 self.prototype也發生改變,這樣並不是我們的本意。所以通過一個空函數 nop 做中轉,能有效的防止這種情況的發生。
bind返回的是函數
if (!Function.prototype.bind) {
Function.prototype.bind = function(obj) {
var _self = this ,args = arguments; return function() { _self.apply(obj, Array.prototype.slice.call(args, 1)); } } }
