文章原地址javascript
ES5
實現 bind
函數以下java
Function.prototype.bind = function(that){
var self = this,
args = arguments.length > 1 ? Array.slice(arguments, 1) : null,
F = function(){};
var bound = function(){
var context = that, length = arguments.length;
if (this instanceof bound){
F.prototype = self.prototype;
context = new F;
}
var result = (!args && !length)
? self.call(context)
: self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments);
return context == that ? result : context;
};
return bound;
}
複製代碼
測試1git
var bar = function() {
console.log(this.x)
}
var foo = {
x: 3
}
var func = bar.bind(foo);
func(); // 3
複製代碼
bar
函數綁定foo
中的x
值,而後輸出3github
bind
函數中最主要的是bound
函數,bound
函數作了哪些事呢?segmentfault
首先context
存儲傳入的that
到context
中,判斷this instanceof bound
,那何時this instanceof bound == true
呢?在測試1中的案例中,this instanceof bound
爲false
,打印此時的this
輸出Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
,發現是window
對象,由於foo
自己就是在window
對象中。app
因此此時直接執行self.call(context)
,返回執行的結果3
,就是咱們測試1中的結果。函數
那何時this instanceof bound == true
呢,並且此時還須要使用空函數F
來獲取主函數的prototype
,post
答案是實例化,何時實例化呢?測試
測試2ui
var bar = function() {
console.log(this.x)
}
bar.prototype.name = function(){
this.name = 'name';
}
var foo = {
x: 3
}
var func = bar.bind(foo);
var newFunc = new func; // undefined
newFunc.name(); // name
複製代碼
對bar.bind(foo)
進行實例化,此時由於進行了new
操做,new
操做作了什麼呢,參考new操做符裏面到底發生了什麼?因此此時的this
爲新生成的bound {}
對象,constructor
爲bound
函數,因此此時this instanceof bound == true
那爲何bar.bind(foo)
把foo
對象傳遞的時候,沒有輸出3
而是undefined
呢?也是由於new
操做,當前的上下文已是新生成的newFunc
函數了。並且當this instanceof bound == true
時,會把bar
的prototype
賦給F
函數,而bound
函數返回的是new F
,因此這時bar
的prototype
也賦給newFunc
了。
咱們看看ES6
的操做,結果和上述例子是同樣的。
var bar = function() {
console.log(this.x)
}
bar.prototype.name = function(){
console.log('name')
}
var foo = {
x: 3
}
var func = bar.bind(foo);
func(); // 3
// 實例化
var newFunc = new func; // undefined
newFunc.name(); // name
複製代碼
總結:
因此bind
函數總共作了哪幾件事呢?
new
操做生成新函數,原函數的prototype
賦給新函數,執行新函數,並返回新函數