if(!Function.prototype.bind){javascript
Function.prototype.bind = function(oThis){php
if(typeof this !=="function"){ //若是不函數拋出異常java
throw new TyperError("")數組
}app
var aArgs = Array.prototype.slice.call(arguments,1), //此處的aArgs是除函數外的參數函數
fToBind = this, //要綁定的對象ui
fNOP = function(){},this
fBound = function(){spa
return fToBind.apply(prototype
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)); } } }