Javascript學習---函式繫結bind()
阿新 • • 發佈:2018-11-07
函式繫結
在前面我們已經知道setTimeout()很容易就會丟失this,看下面的例子:
let user = {
firstName: "John",
sayHi() {
alert(`Hello, ${this.firstName}!`);
}
};
setTimeout(user.sayHi, 1000); // Hello, undefined!
這裡this.firstName的值為undefined,因為setTimeout()在接收user.sayHi()時與user物件是隔離的,故this就丟失了。它類似於一下的操作:
let f = user.sayHi; setTimeout(f, 1000); // lost user context
因為在瀏覽器中執行,所以丟失了上下文物件user後,this所指向的物件就是全域性物件window,故為undefined
解決方案
(1)使用包裝器
let user = {
firstName: "John",
sayHi() {
alert(`Hello, ${this.firstName}!`);
}
};
setTimeout(function() {
user.sayHi(); // Hello, John!
}, 1000);
setTimeout的第一個引數直接使用user.sayHi(),此時setTimeout就會根據詞法環境接受user物件作為上下文物件,下面是簡寫的例子:
setTimeout(() => user.sayHi(), 1000); // Hello, John!
但是有一個問題要注意的是,如果setTimeout要呼叫的執行函式內容在排程前被修改,那麼setTimeout觸發的執行函式為修改過的內容,例如:
let user = { firstName: "John", sayHi() { alert(`Hello, ${this.firstName}!`); } }; setTimeout(() => user.sayHi(), 1000); // ...within 1 second user = { sayHi() { alert("Another user in setTimeout!"); } }; // Another user in setTimeout?!?
為了結果這個問題,我們需要用bind()來繫結上下文物件
(2)bind()
Javascript的函式都內建了bind()方法來繫結上下文物件,它的語法如下:
// more complex syntax will be little later
let boundFunc = func.bind(context);
bind()預設返回修改過上下文物件(this=context)的新函式(boundFunc)
看下面的例子:
let user = {
firstName: "John"
};
function func(phrase) {
alert(phrase + ', ' + this.firstName);
}
// bind this to user
let funcUser = func.bind(user);
funcUser("Hello"); // Hello, John (argument "Hello" is passed, and this=user)
上述例子中,當我們呼叫funcUser(...)的時候,它會去呼叫func()並且修改上下文物件this=context
現在我們嘗試繫結物件方法,例如:
let user = {
firstName: "John",
sayHi() {
alert(`Hello, ${this.firstName}!`);
}
};
let sayHi = user.sayHi.bind(user); // (*)
sayHi(); // Hello, John!
setTimeout(sayHi, 1000); // Hello, John!
如果一個物件有許多的方法需要繫結上下文物件,我們可以使用bindAll()來繫結所有的方法,或者我們可以遍歷物件的所有屬性方法來繫結this,例如:
for (let key in user) {
if (typeof user[key] == 'function') {
user[key] = user[key].bind(user);
}
}