【譯】Javascript: call()、apply() 和 bind()
- 原文地址:Javascript: call(), apply() and bind()
- 原文作者:Omer Goldberg
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:YueYong
- 校對者:Guangping, sun
Javascript: call()、apply() 和 bind()
回顧一下 “this”
我們瞭解到,在面向物件的 JS 中,一切都是物件。因為一切都是物件,我們開始明白我們可以為函式設定並訪問額外的屬性。
通過原型給函式設定屬性並且新增其他方法非常棒...但是我們如何訪問它們?!???!
當他說 “myself” 時,他的確意味著 ‘this’
我們介紹過 this
關鍵字。我們瞭解到每個函式都會自動獲取此屬性。所以這時,如果我們建立一個有關我們函式執行上下文的抽象模型(我不是唯一一個這麼做的人!...對嗎?!?!),它看起來就會像這樣:
我們花了一些時間來熟悉 this
關鍵字,但是一旦我們這樣做了,我們就開始意識到它是多麼有用了。this
在函式內部使用,並且總是引用單個物件 — 這個物件會在使用 “this” 的地方呼叫函式。
但是生活肯定都不是完美的。有時候我們會失去 this
的引用。當這種情況發生時,我們最終使用了令人困惑的解決方法去儲存我們對於 this
第 31 行 :(
那為什麼我需要儲存 this
引用呢?因為在 deleteBtn.addEventListener 中,this
指向了 deleteBtn 物件。這並不太好。有更好的解決方案嗎?
call()、apply() 和 bind() — 一個新的希望
到目前為止,我們已將函式視為由名稱(可選,也可以是匿名函式)及其在呼叫時執行的程式碼所組成的物件。但這並不是全部真相。作為一個 熱愛真理的人,我必須讓你知道一個函式實際上看起來更接近下面的影象:
這是什麼???????別擔心!現在,我將通過示例介紹每個函式中出現的這 3 種類似方法。真是很讓人興奮呢!
bind()
官方文件說: bind()
方法建立一個新函式,在呼叫時,將其 this
關鍵字設定為所需的值。(它實際上談論了更多的東西,但我們將把它留到下一次講)
這非常強大。它讓我們在呼叫函式時明確定義 this
的值。我們來看看 cooooode:
var pokemon = {
firstname: 'Pika',
lastname: 'Chu ',
getPokeName: function() {
var fullname = this.firstname + ' ' + this.lastname;
return fullname;
}
};
var pokemonName = function() {
console.log(this.getPokeName() + 'I choose you!');
};
var logPokemon = pokemonName.bind(pokemon); // creates new object and binds pokemon. 'this' of pokemon === pokemon now
logPokemon(); // 'Pika Chu I choose you!'
複製程式碼
在第 14 行使用了 bind()方法
。
我們來逐個分析。 當我們使用了 bind()
方法:
- JS 引擎建立了一個新的
pokemonName
的例項,並將pokemon
繫結到this
變數。 重要的是要理解它複製了 pokemonName 函式。 - 在建立了
pokemonName
函式的副本之後,它可以呼叫logPokemon()
方法,儘管它最初不在pokemon
物件上。它現在將識別其屬性(Pika 和 Chu)及其方法。
很酷的是,在我們 bind() 一個值後,我們可以像使用任何其他正常函式一樣使用該函式。我們甚至可以更新函式來接受引數,並像這樣傳遞它們:
var pokemon = {
firstname: 'Pika',
lastname: 'Chu ',
getPokeName: function() {
var fullname = this.firstname + ' ' + this.lastname;
return fullname;
}
};
var pokemonName = function(snack, hobby) {
console.log(this.getPokeName() + 'I choose you!');
console.log(this.getPokeName() + ' loves ' + snack + ' and ' + hobby);
};
var logPokemon = pokemonName.bind(pokemon); // creates new object and binds pokemon. 'this' of pokemon === pokemon now
logPokemon('sushi', 'algorithms'); // Pika Chu loves sushi and algorithms
複製程式碼
call(), apply()
call() 方法的官方文件說:call()
方法呼叫一個給定 this
值的函式,並單獨提供引數。
這意味著,我們可以呼叫任何函式,並明確指定 this
應該在呼叫函式中引用的內容。真的類似於 bind()
方法!這絕對可以讓我們免於編寫 hacky 程式碼(即使我們仍然是 hackerzzz)。
bind()
和 call()
之間的主要區別在於 call()
方法:
- 支援接受其他引數
- 當它被呼叫的時候,立即執行函式。
call()
方法不會複製正在呼叫它的函式。
call()
和apply()
使用於完全相同的目的。 它們工作方式之間的唯一區別是 call()
期望所有引數都單獨傳遞,而 apply()
需要所有引數的陣列。例如:
var pokemon = {
firstname: 'Pika',
lastname: 'Chu ',
getPokeName: function() {
var fullname = this.firstname + ' ' + this.lastname;
return fullname;
}
};
var pokemonName = function(snack, hobby) {
console.log(this.getPokeName() + ' loves ' + snack + ' and ' + hobby);
};
pokemonName.call(pokemon,'sushi', 'algorithms'); // Pika Chu loves sushi and algorithms
pokemonName.apply(pokemon,['sushi', 'algorithms']); // Pika Chu loves sushi and algorithms
複製程式碼
注意,apply 接受陣列,call 接受每個單獨的引數。
這些存在於每一個 JS 函式的內建方法都非常有用。即使你最終沒有在日常程式設計中使用它們,你仍然會在閱讀其他人的程式碼時經常遇到它們。
如果您有任何疑問,請一如既往地通過 Instagram 與我們聯絡。❤
如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。