bind() 方法創建一個新的函數,在 bind() 被調用時,這個新函數的 this 被指定為 bind() 的第一個參數,而其餘參數將作為新函數的參數,供調用時使用。
從MDN對於bind的描述來看:
- 返回值是一個函數,而不是執行結果
- this值會指向第一個參數
- 其餘參數會作為新函數的參數
看個例子:
function test(name, age) {
console.log(this.name);
this.name = name;
this.age = age;
console.log(this.name, this.age);
}
var obj = {
name: 'Willem'
};
var bindFn = test.bind(obj, 'Wei');
bindFn(18);
// Willem
// Wei, 18
從上面的代碼就可以看出來,bind函數執行之後,bindFn的this值指向了obj,並且在bind的時候傳入的參數和在執行bindFn時傳入的參數都成功的傳入了test函數。
那代碼就呼之欲出了啊。
Function.prototype.wbind = function() {
var context = [].shift.call(arguments);
var args = [].slice.call(arguments);
var self = this;
return function() {
var innerArgs = [].slice.call(arguments);
self.apply(context, args.concat(innerArgs));
}
}
相關:模擬實現Javascript中的call和apply
既然bind返回的是一個函數,那我有一個大膽的想法,如果我把這個返回的函數作為一個構造函數會怎樣呢?改造一下上面的那個例子:
function test(name, age) {
console.log(this.name);
this.name = name;
this.age = age;
console.log(this.name, this.age);
}
test.prototype.sayHi = function() {
console.log('Hi, ' + this.name);
}
var obj = {
name: 'Willem'
};
var bindFn = test.bind(obj, 'Wei');
var instance = new bindFn(18);
// undefined
// Wei,18
instance.sayHi(); // Hi, Wei
console.log(obj.name); // Willem
咦,obj對象裏面明明是有name屬性的啊,為啥第一次輸出的是undfined呢?明明傳入了name屬性為"Wei",為啥obj.name還是"Willem"呢?
其實是因為this並沒有指向obj了,而是指向了instance。總結一下,將返回的函數作為普通函數使用時,函數的this指向bind執行時傳入的第一個參數;將返回的函數作為構造函數使用時,函數的this指向實例,並且該實例將會繼承原函數原型上的屬性和方法。
這時候,我們再來改一改wbind函數:
Function.prototype.wbind = function() {
var context = [].shift.call(arguments);
var args = [].slice.call(arguments);
var self = this;
var fBound = function() {
var innerArgs = [].slice.call(arguments);
// 做構造函數時,this指向實例
self.apply(this instanceof fBound ? this : context, args.concat(innerArgs));
}
// 實例需要繼承原函數原型上的方法和屬性
// 使用fNOP中轉一次是因為直接將this.prototype賦值到fNOP.prototype時
// 當修改fNOP的prototype時,this.prototype也會被修改
var fNOP = function() {}
if (this.prototype) {
fNOP.prototype = this.prototype;
}
// fBound.prototype = { __proto__: { this.prototype } }
// 相當於是中間多了一個__proto__,因為原型鏈的緣故,所以多一層__proto__沒有什麼影響
fBound.prototype = new fNOP();
return fBound;
}
相關:
模擬實現js中的new操作符
簡單説説原型和原型鏈
使用ts模擬實現js中的一些函數和屬性
以上,就是bind的相關內容。