今天研究了一下es5中的bind函數如何用es3的語法來實現,下面是一個簡單的bind函數實現:
bind函數
Function.prototype.bind=function(oThis){
var self=this;
var args=Array.prototype.slice.call(arguments,1);
var result=function(){
return self.apply(oThis,args.concat(Array.prototype.slice.call(arguments)));
};
var temp=function(){};
temp.prototype=this.prototype;
result.prototype=new temp();
return result;
};
測試代碼
var A={
name: 'jc',
print: function(title){
console.log(title+this.name);
}
};
var func=A.print.myBind(A);
func('red'); //jcred
分析
整個bind函數一共做了兩件事:
首先通過數組的原型方法把bind函數參數中除了oThis對象以外的參數保存到args中,然后再講args和調用函數傳入參數列表合并,并通過調用Function.prototype.apply方法將oThis綁定到調用函數的this上,并傳入合并后的參數列表。
因為調用apply方法返回了一個新的函數對象,丟失了原函數對象的原型屬性,所以還要將新的函數對象的prototype屬性引用原函數對象的原型對象。
之所以不采用result.prototype=this.prototype這種寫法,而是使用了一個中間層對象temp,是因為不想通過修改result.prototype就修改了原函數對象的原型對象。
附上bind函數官方文檔的實現
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 && oThis
? this
: oThis || window,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}