JavaScript 中的 Bind()、Apply() 和 Call():鮮為人知的差異

每個開發(fā)者都應(yīng)該充分理解它們的工作原理,并能夠辨別它們之間的微妙差異。
首先要知道,JavaScript 函數(shù)是“一等公民”。這意味著它們都是對象值——所有函數(shù)都是 Function 類的實(shí)例,擁有方法和屬性:

因此,bind()、apply() 和 call() 是每個 JavaScript 函數(shù)都具備的三個基本方法。
bind()
你還記得 React 的早期痛苦時代嗎?當(dāng)時我們?nèi)栽谑褂妙惤M件,并且事件處理程序通常是這樣寫的:

這只是 bind() 的眾多應(yīng)用之一——一個嚴(yán)重被低估的 JavaScript 方法。
沒有 bind(),sayName() 會一團(tuán)糟——alert() 根本不會生效。
這是因?yàn)?React 在內(nèi)部對這個方法做了一些處理,導(dǎo)致 this 的引用在方法內(nèi)部完全被搞亂了。
最初,sayName 顯示 alert 是沒有問題的——就像在這個類中的另一個方法一樣:


但是,React 在后臺對 greet 事件處理程序做了什么呢?它將其重新分配給另一個變量:

所以 this 發(fā)生了什么?它無法再被找到:

這時候 bind 派上了用場——它將 this 綁定到你選擇的任意實(shí)例對象上:
const boundGreet = this.greet.bind(this);所以我們將函數(shù)綁定到了對象——也就是 bind 的目標(biāo)對象。
(我知道正確的說法是“bound”,但讓我們像說“indexes”代替“indices”一樣說“binded”吧)。

bind 是不可變的——它返回綁定后的函數(shù),而不會改變原始函數(shù)。
這讓我們可以多次使用它:

對比 call()
call 和 bind 之間只有一個很小的區(qū)別。
bind 創(chuàng)建一個綁定后的函數(shù),可以多次使用。
而 call 呢?它會立即創(chuàng)建一個臨時的綁定函數(shù)并調(diào)用它:

所以 call() 基本上就是 bind() + 一次調(diào)用。
但是當(dāng)函數(shù)有參數(shù)時怎么辦?該如何處理呢?
完全沒問題——只需將它們作為更多參數(shù)傳遞給 call:

實(shí)際上,你也可以用 bind() 做同樣的事情:

對比 apply()
一開始你可能會認(rèn)為 apply() 與 call() 完全一樣:

但是就像 bind() 和 call() 之間有微妙的區(qū)別一樣,apply() 和 call() 之間也有一個細(xì)微的區(qū)別:參數(shù)的傳遞方式。

一個記憶技巧可以幫助你記住它們的區(qū)別:
- call() 適用于用逗號分隔的參數(shù)
- apply() 適用于數(shù)組
總結(jié)
- bind()——綁定 this 并返回一個新的函數(shù),可以重復(fù)使用。
- call()——綁定并調(diào)用函數(shù),使用逗號分隔的參數(shù)傳遞。
- apply()——綁定并調(diào)用函數(shù),使用數(shù)組傳遞參數(shù)。
這些函數(shù)方法是理解 JavaScript 函數(shù)和 this 關(guān)鍵字的基礎(chǔ),也是編寫健壯代碼的重要工具。



























