JavaScript 中的 Bind()、Apply() 和 Call():鮮為人知的差異
每個開發者都應該充分理解它們的工作原理,并能夠辨別它們之間的微妙差異。
首先要知道,JavaScript 函數是“一等公民”。這意味著它們都是對象值——所有函數都是 Function 類的實例,擁有方法和屬性:
因此,bind()、apply() 和 call() 是每個 JavaScript 函數都具備的三個基本方法。
bind()
你還記得 React 的早期痛苦時代嗎?當時我們仍在使用類組件,并且事件處理程序通常是這樣寫的:
這只是 bind() 的眾多應用之一——一個嚴重被低估的 JavaScript 方法。
沒有 bind(),sayName() 會一團糟——alert() 根本不會生效。
這是因為 React 在內部對這個方法做了一些處理,導致 this 的引用在方法內部完全被搞亂了。
最初,sayName 顯示 alert 是沒有問題的——就像在這個類中的另一個方法一樣:
但是,React 在后臺對 greet 事件處理程序做了什么呢?它將其重新分配給另一個變量:
所以 this 發生了什么?它無法再被找到:
這時候 bind 派上了用場——它將 this 綁定到你選擇的任意實例對象上:
const boundGreet = this.greet.bind(this);
所以我們將函數綁定到了對象——也就是 bind 的目標對象。
(我知道正確的說法是“bound”,但讓我們像說“indexes”代替“indices”一樣說“binded”吧)。
bind 是不可變的——它返回綁定后的函數,而不會改變原始函數。
這讓我們可以多次使用它:
對比 call()
call 和 bind 之間只有一個很小的區別。
bind 創建一個綁定后的函數,可以多次使用。
而 call 呢?它會立即創建一個臨時的綁定函數并調用它:
所以 call() 基本上就是 bind() + 一次調用。
但是當函數有參數時怎么辦?該如何處理呢?
完全沒問題——只需將它們作為更多參數傳遞給 call:
實際上,你也可以用 bind() 做同樣的事情:
對比 apply()
一開始你可能會認為 apply() 與 call() 完全一樣:
但是就像 bind() 和 call() 之間有微妙的區別一樣,apply() 和 call() 之間也有一個細微的區別:參數的傳遞方式。
一個記憶技巧可以幫助你記住它們的區別:
- call() 適用于用逗號分隔的參數
- apply() 適用于數組
總結
- bind()——綁定 this 并返回一個新的函數,可以重復使用。
- call()——綁定并調用函數,使用逗號分隔的參數傳遞。
- apply()——綁定并調用函數,使用數組傳遞參數。
這些函數方法是理解 JavaScript 函數和 this 關鍵字的基礎,也是編寫健壯代碼的重要工具。