|
|
|
|
|
在前文,非常詳細(xì)的介紹了JS里this的上下文對(duì)象及用法,知道了this
是由其上下文決定的——它是全局的、在對(duì)象中、在構(gòu)造函數(shù)或類中、或在 DOM 事件處理程序上,它是隱式引用的。但是,如果使用call
、apply
或bind
方法,你可以明確確定this
應(yīng)該引用什么。
何時(shí)使用call、apply或bind?
何時(shí)使用call
、apply
或bind
,取決于程序的上下文。bind
當(dāng)你想使用事件來(lái)訪問(wèn)另一個(gè)類中的一個(gè)類的屬性時(shí),它會(huì)特別有用。例如,如果你要編寫一個(gè)簡(jiǎn)單的游戲,你可能會(huì)將用戶界面和 I/O 分離到一個(gè)類中,而將游戲邏輯和狀態(tài)分離到另一個(gè)類中。由于游戲邏輯需要訪問(wèn)輸入,例如按鍵和單擊,你可能希望bind
事件訪問(wèn)游戲邏輯類的this
值。
重要的部分是知道如何確定this
所指的對(duì)象,你可以像前文JS里this的上下文對(duì)象及用法介紹的那樣,隱含地執(zhí)行此操作,或者使用接下來(lái)將學(xué)習(xí)的三種方法顯式地執(zhí)行此操作。
call和apply的相同之處
call
和apply
非常相似——它們調(diào)用具有指定this
上下文和可選參數(shù)的函數(shù)。call
和apply
之間的唯一區(qū)別是,call
需要一個(gè)接一個(gè)地傳遞參數(shù),而apply
將參數(shù)作為一個(gè)數(shù)組。
在此示例中,我們將創(chuàng)建一個(gè)對(duì)象,并創(chuàng)建一個(gè)引用this
但沒(méi)有this
上下文的函數(shù)。
const webkaka = {
name: '卡卡網(wǎng)',
domainName: 'webkaka.com',
}
function describe() {
console.log(`${this.name} 的域名是 ${this.domainName}.`)
}
describe()
輸出
"undefined 的域名是 undefined"
由于describe
并且webkaka
沒(méi)有關(guān)聯(lián),因此單獨(dú)調(diào)用describe
只會(huì)打印 undefined
,因?yàn)樗趯ふ胰謱?duì)象上的那些屬性。
但是,你可以使用call
和apply
調(diào)用函數(shù)webkaka
的this
上下文。
describe.call(webkaka)
// or:
describe.apply(webkaka)
輸出
"卡卡網(wǎng) 的域名是 webkaka.com"
當(dāng)這些方法被應(yīng)用,在describe
和webkaka
之間會(huì)有一個(gè)新的聯(lián)系,現(xiàn)在讓我們確認(rèn)this
到底是什么。
function printThis() {
console.log(this)
}
printThis.call(webkaka)
// or:
printThis.apply(webkaka)
輸出
{name: "卡卡網(wǎng)", domainName: "webkaka.com"}
在這種情況下,this
實(shí)際上成為作為參數(shù)傳遞的對(duì)象。
這是call
和apply
是如何相同的。
call和apply的微妙區(qū)別
除了能夠?qū)?code>this上下文作為第一個(gè)參數(shù)傳遞之外,還可以傳遞其他參數(shù)。
const webkaka = {
name: '卡卡網(wǎng)',
domainName: 'webkaka.com',
}
function printThis() {
console.log(this)
}
function longDescribe(title, year) {
console.log(`${this.name} 的域名是 ${this.domainName}, 它的標(biāo)題是 ${title} , 它創(chuàng)建于 ${year} 年。` )
}
longDescribe.call(webkaka, '卡卡測(cè)速網(wǎng)', 2009);
你要傳遞的每個(gè)附加值,用call
時(shí),它們都作為一個(gè)附加參數(shù)發(fā)送。
輸出
卡卡網(wǎng) 的域名是 webkaka.com, 它的標(biāo)題是 卡卡測(cè)速網(wǎng) , 它創(chuàng)建于 2009 年。
如果你嘗試使用apply
發(fā)送完全相同的參數(shù),則會(huì)發(fā)生以下情況:
longDescribe.apply(webkaka, '卡卡測(cè)速網(wǎng)', 2009);
輸出
Uncaught TypeError: second argument to Function.prototype.apply must be an array
對(duì)于apply
,你必須傳遞數(shù)組中的所有參數(shù)。
longDescribe.apply(webkaka, ['卡卡測(cè)速網(wǎng)', 2009]);
輸出
卡卡網(wǎng) 的域名是 webkaka.com, 它的標(biāo)題是 卡卡測(cè)速網(wǎng) , 它創(chuàng)建于 2009 年。
單獨(dú)傳遞參數(shù)或以數(shù)組形式傳遞參數(shù)之間的區(qū)別是微妙的,但要注意這一點(diǎn)很重要。使用起來(lái)apply
可能更簡(jiǎn)單方便,因?yàn)槿绻承﹨?shù)細(xì)節(jié)發(fā)生變化,它不需要更改函數(shù)調(diào)用。
this與bind方法
call
和apply
都是一次性使用的方法——如果你用this
上下文調(diào)用方法,它會(huì)擁有它,但原始函數(shù)將保持不變。
有時(shí),你可能需要在另一個(gè)對(duì)象的this
上下文中反復(fù)使用一個(gè)方法,在這種情況下,你可以使用bind
方法創(chuàng)建一個(gè)具有顯式綁定this
的全新函數(shù)。
const webkaka = {
name: '卡卡網(wǎng)',
domainName: 'webkaka.com',
}
function describe() {
console.log(`${this.name} 的域名是 ${this.domainName}`)
}
const Summary = describe.bind(webkaka);
Summary();
輸出
卡卡網(wǎng) 的域名是 webkaka.com
在這個(gè)例子中,每次你調(diào)用 Summary
,它總是會(huì)返回綁定到它的this
原始值。嘗試將新this
上下文綁定到它會(huì)失敗,因此你始終可以相信綁定函數(shù)返回你期望的this
值。
const webkaka = {
name: '卡卡網(wǎng)',
domainName: 'webkaka.com',
}
function describe() {
console.log(`${this.name} 的域名是 ${this.domainName}`)
}
const Summary = describe.bind(webkaka);
const webkaka2 = {
name: '卡卡網(wǎng)',
domainName: 'webkaka.com',
}
Summary.bind(webkaka2);
Summary();
輸出
卡卡網(wǎng) 的域名是 webkaka.com
盡管此示例嘗試Summary
再次綁定,但它保留了第一次綁定時(shí)的原始this
上下文。
總結(jié)
本文詳細(xì)介紹了JS里this
與call()
apply()
和bind()
的用法相同及區(qū)別,我們?cè)谑褂脮r(shí)應(yīng)該明白其中的含義,以免用錯(cuò)方法而得不到期望的結(jié)果。
參考文章