在 JavaScript 中,改變函數內部 this 的指向常見的方式有 call()、apply()、bind(),而這三種方式又存在些微差異。
call()
call() 方法會呼叫(執行)一個函數,且可以同時改變函數內部的 this 指向。
語法:
1 | fun.call(thisArg ,arg1, arg2, ...); |
參數說明:
- thisArg:在函式運行時的
this指向,若省略則僅執行函式而不改變this指向。 - arg1, arg2, …:傳遞的參數(可省略)。
例如:
在非嚴格模式下,函式 foo 中的 this 指向的原本是 window,因在此例子中,foo 其實是屬於 window 物件的一個方法。(若在嚴格模式下,則為 undefined)
1 | var obj = { |
剛提到,call() 會呼叫(執行)函式,但若無給第一個參數,則僅會呼叫函式而不會改變 this 指向,所以除了用 foo() 執行 foo 函式之外,也可以透過 call() 來呼叫(當然不需要多此一舉)。
1 | foo.call(); // window |
現在除了呼叫 foo 函式,同時想要將函式 foo 裡的 this 指向改為 obj,可以使用 call() 來達成。
1 | foo.call(obj); // obj |
還可以傳遞一些參數。
1 | var obj = { |
實現繼承
call() 也可以用來實現繼承。
1 | function Person(name, age){ |
apply()
使用 apply() 會呼叫一個函數,同時可以改變函數內部 this 指向,apply() 與 call() 幾乎一樣,最大的不同是 call() 接受一連串的參數,而 apply() 接受一組陣列(或類陣列)形式的參數。
語法:
1 | fun.apply(thisArg, [argsArray]); |
參數說明:
- thisArg:在函式運行時的
this指向。 - [argsArray]:傳遞的參數必須為陣列或類陣列(可省略)。
bind()
bind() 能改變 this 指向,但不會呼叫(執行)函數,會 copy 並返回一個新的函數。
語法:
1 | fun.bind(thisArg, arg1, arg2, ...) |
參數說明:
- thisArg:在 fun 函數運行時指定的
this值。 - arg1, arg2, …:傳遞其他參數(可省略)。
例如:
使用 bind() 將函式 foo 裡的 this 指向改為 obj,同時傳遞 1 和 2 兩個引數,有別於 call() 與 apply(),bind() 並不會呼叫執行 foo 函式,僅會返回一個新的函式。
1 | var obj = { |
因 bind() 並不會呼叫執行 foo 函式,而是返回一個新的函式,若想要同時執行 foo,則需手動加上 ()。
1 | foo.bind(obj, 1, 2)(); |
現在來看看返回的新函式長什麼樣子,可以打開瀏覽器,並輸入以下代碼。
1 | var obj = { |
印出 newFoo:

咦? newFoo 不就是 foo 嗎?
再試著輸入以下代碼,事實證明 newFoo 不等於 foo。
1 | console.log(newFoo === foo); // false |
在開發中,最常使用的應該是 bind(),因為很多情況下我們只是想改變 this,不想同時執行函數。
例如現在有一個按鈕,想要在用戶點擊後,禁用此按鈕 3 秒。
1 | <button>按鈕</button> |
若直接在定時器裡使用匿名 function(){} 形式的 callback,定時器裡的 this 指向的是 window。
1 | const btn = document.querySelector('button'); |
這時候 bind() 就可以派上用場了,因為不想要在改變 this 的同時執行 this.disabled = false,而是希望透過定時器 3 秒後執行,此時就不適用 call() 與 apply()。
1 | const btn = document.querySelector('button'); |
當然,也可以直接將定時器裡的 callback function 改成箭頭函式(arrow function)的形式來解決。
1 | const btn = document.querySelector('button'); |
總結
call()、apply()、bind() 皆可以改變函數內部的 this ,三者的差異在於:
| 自動呼叫函數 | 參數(可省略) | |
|---|---|---|
| call() | ⭕️ | arg1, arg2, … |
| apply() | ⭕️ | [arg1, arg2, …] |
| bind() | ❌ | arg1, arg2, … |
參考資料: