函數(shù)對象的bind()方法會創(chuàng)建一個新函數(shù),bind()方法返回由指定的this值和初始化參數(shù)改造的原函數(shù)拷貝。
語法 fun.bind(thisArg[, arg1[, arg2[, ...]]])
比如foo.bind(bar, arg1, arg2),它返回一個新函數(shù),就是說,內(nèi)存中出現(xiàn)了一個匿名的新函數(shù),暫且叫他newfoo吧,未來newfoo被調(diào)用的時候,它的this值指向bar的引用,newfoo的參數(shù)是foo的所有參數(shù)。
下面是一個最簡單的例子,可以看到?jīng)]啥奇怪的,this.x的this指向的是調(diào)用方法的對象,也就是module,module的x屬性的值是81,所以輸出81。
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
console.log(module.getX()); // 81
然后,一個新手想把module.getX方法賦值給一個新的變量,然后打算以后用這個變量來運行function() { return this.x; },于是他寫成了:
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 返回 81
var retrieveX = module.getX;
console.log(retrieveX()); // 返回 9
為什么返回9?因為var retrieveX = module.getX相當于var retrieveX = function() { return this.x; },這時候this指向window,所以返回9。
這下是不是傻逼了?怎么避免這種傻逼?給module.getX方法綁定新的this指向就可以了。
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 返回 81
var retrieveX = module.getX.bind(module);
console.log(retrieveX()); // 返回 81
也就是說,retrieveX函數(shù)的this依然指向module。
bind()的另一個最簡單的用法是,使一個函數(shù)擁有預設(shè)的初始參數(shù)。這些參數(shù)(如果有的話)作為bind()的第二個參數(shù)跟在this(或其他對象)后面,之后它們會被插入到目標函數(shù)的參數(shù)列表的開始位置,傳遞給綁定函數(shù)的參數(shù)會跟在它們的后面。
比如,我們現(xiàn)有一個很簡單的做加法的函數(shù)叫foo:
function foo(a, b) {
return a + b;
}
我開始用這個函數(shù)解決各種問題,突然有個場景是,我已知第一個參數(shù)是41,第二個參數(shù)不確定。那么我是不是要重新寫一個幾乎一模一樣的函數(shù)呢?當然No。由于我舉例的foo函數(shù)特別簡單,你當然覺得重寫一下也不費什么勁,但如果實踐中foo函數(shù)很長很復雜呢?現(xiàn)在有bind,就可以一句創(chuàng)建出一個新函數(shù)。
function foo(a, b) {
return a + '--' + b;
}
var bar = foo.bind(null, 41); // 第一個參數(shù)是null或者undefined的話,bar的this不改變指向,只是第一個參數(shù)永遠傳入41
console.log(bar(3)); // 41--3,第一個參數(shù)是41,第二個是3。
當然你可能說,不用bind()也可以實現(xiàn),比如下面用高階函數(shù)實現(xiàn):
function foo(a, b) {
return a + '--' + b;
}
function bar(b) {
return foo(41, b);
};
console.log(bar(3)); // 41--3
bind()和高階函數(shù)兩種都可以,bind()算是另一套解決方案。
現(xiàn)在我又有新要求,頁面有一個按鈕,點擊之后3秒之后打印按鈕上的文字,不注意this指向的話,會是下面這樣:
document.getElementById('btn').onclick = function() {
var foo = function() {
console.log(this.innerText); // undefined
};
setTimeout(foo, 3000);
}
怎么改?foo的bind方法傳入的第一個參數(shù)就是點擊事件的回調(diào)函數(shù),回調(diào)函數(shù)的this指向按鈕DOM對象,所以foo能輸出按鈕上的文字。
document.getElementById('btn').onclick = function() {
var foo = function() {
console.log(this.innerText); // undefined
};
setTimeout(foo.bind(this), 3000);
}