[譯] Javascript: call()、apply() 和 bind()

僱個城管打天下發表於2019-03-02

回顧一下 “this”

我們瞭解到,在物件導向的 JS 中,一切都是物件。因為一切都是物件,我們開始明白我們可以為函式設定並訪問額外的屬性。

通過原型給函式設定屬性並且新增其他方法非常棒…但是我們如何訪問它們?!???!

[譯] Javascript: call()、apply() 和 bind()

當他說 “myself” 時,他的確意味著 ‘this’

我們介紹過 this 關鍵字。我們瞭解到每個函式都會自動獲取此屬性。所以這時,如果我們建立一個有關我們函式執行上下文的抽象模型(我不是唯一一個這麼做的人!…對嗎?!?!),它看起來就會像這樣:

[譯] Javascript: call()、apply() 和 bind()

我們花了一些時間來熟悉 this 關鍵字,但是一旦我們這樣做了,我們就開始意識到它是多麼有用了。this 在函式內部使用,並且總是引用單個物件 — 這個物件會在使用 “this” 的地方呼叫函式

但是生活肯定都不是完美的。有時候我們會失去 this 的引用。當這種情況發生時,我們最終使用了令人困惑的解決方法去儲存我們對於 this 的引用。讓我們通過 localSorage 練習來看看這個方法吧:

[譯] Javascript: call()、apply() 和 bind()

第 31 行 ?

那為什麼我需要儲存 this 引用呢?因為在 deleteBtn.addEventListener 中,this 指向了 deleteBtn 物件。這並不太好。有更好的解決方案嗎?


call()、apply() 和 bind() — 一個新的希望

到目前為止,我們已將函式視為由名稱(可選,也可以是匿名函式)及其在呼叫時執行的程式碼所組成的物件。但這並不是全部真相。作為一個 熱愛真理的人,我必須讓你知道一個函式實際上看起來更接近下面的影像:

[譯] Javascript: 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() 方法:

  1. JS 引擎建立了一個新的 pokemonName 的例項,並將 pokemon 繫結到 this 變數。 重要的是要理解它複製了 pokemonName 函式。
  2. 在建立了 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() 方法:

  1. 支援接受其他引數
  2. 當它被呼叫的時候,立即執行函式。
  3. 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 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章