本篇為 [JS201] 進階 JavaScript:那些你一直搞不懂的地方 這門課程的學習筆記。如有錯誤歡迎指正!
1 | 學習目標: |
從物件導向到 this
在上一篇JavaScript 進階 - 物件導向 & Prototype 筆記中,其實我們就有提到 this 相關概念。this 的主要用途就在於物件導向,用來指哪個 instance 在呼叫這個 function,透過 this 我們能夠進一步操作。
那如果是在和物件導向無關的情況下,呼叫 this 會代表什麼?
Global context 下的 this
如果在全域環境下呼叫 this,根據不同執行環境(瀏覽器或 node.js),預設值可能會是 global 或 window:
在 node.js 運行
1 | function test() { |

在瀏覽器運行
1 | function test() { |

use strict 嚴格模式
在不需要的地方呼叫 this,卻還是會有預設值 global 或 window。這時候,只要設定 'use strict'(嚴格模式)就能避免,this 的預設值會是 undefined:
1 | ; |
DOM 元素中的 this
此外,對 DOM 元素進行事件監聽時,this 就代表當下操作的元素,其實非常直覺。例如監聽按鈕的點擊事件,那 this 就會是那個按鈕:
1 | document.querySelector('.btn').addEventListener('click', function() { |
因此我們可以說,除了在物件導向跟 DOM 之外,this 是沒有意義的。
Function context 下的 this
在 function 裡面時,this 的值是什麼取決於該 function 是怎麼被呼叫的。
也就是說,function 沒有被呼叫的時候,預設值就會是 window, global 或 undefined。一旦某個 function 被呼叫時,裡面的 this 就可以理解成,是指向誰在 call 這個 function:
1 | var obj = { |
其中,bar() 這種呼叫函式的方法,其實是 .call() 的語法糖,要更詳細了解呼叫 function 背後在做的事,就要深入理解 .call()、.apply()、bind() 的行為。
另外兩種呼叫 function 的方法:call 與 apply
.call()
第一個值傳入什麼 this 就是什麼。
1 | ; |
.apply()
和 .call() 一樣,第一個值傳入什麼 this 就是什麼,差異在於第二個參數會接一個 array。
可由下方範例來比較三種方式呼叫 function 的差異:
1 | ; // 嚴格模式 |
透過 .call 和 .apply 的第一個參數,我們可以設定 function 中 this 的值。兩者差別在於,一個可以傳入無限的參數,另外一個只能傳入兩個參數;一個要用 array 帶入參數,另一個則否。
此外,我們也可以把一般呼叫 function 的方式都轉成 call 的形式:
1 | const obj = { |
再舉一個例子,透過 call 來呼叫 function,我們就能夠指定 this 的值:
1 | function hello() { |
如何判斷 this 的值
因為 this 是針對物件導向設計的,從以下範例,可知道 this 就是 obj 物件本身:
1 | ; |
重點就是,this 的值和程式碼在哪無關,而是和怎麼呼叫有關係:
1 | ; |
結果卻會得到不同結果,這是因為 obj 呼叫 function,所以 this 會指向 obj;另一方面,this 所在的 instance 中,沒有被 func 呼叫,所以會得到 undefined。
我們可以透過 .call() 來看看 this 指的是什麼:
1 | ; |
.bind():強制綁定 this
除了 .call() 和 .apply(),我們還可以利用 .bind() 來強制綁定 this 的值,但需注意的是,一旦綁定之後就不能再用別的方法進行更改。
將前面提到的例子修改成 .bind(),這裡需注意 .bind() 會是直接回傳一個 function:
1 | ; |
利用 .bind() 就可以綁定 this 的值,也就是鎖定想要呼叫的區域,即便後面再 .call() 指定 this 的值也無法改變。
牛刀小試
以下範例預設在嚴格模式進行:
1 | ; |
思考步驟:
1 | 1. log(); |
arrow function 的 this
arrow function 本身其實沒有 this,在 arrow function 裡面的 this,其實就和 arrow function 外部的 this 是同一個東西。
先以一般宣告 function 為例:
1 | class Test { |
在瀏覽器上的運行結果,會發現第二個 this 等於全域的 Window:

也就是說,在 100 毫秒後才呼叫,其實作用就等同於在全域呼叫這個 function:
1 | function() { |
但如果改成箭頭函式,結果就會不同了:
1 | class Test { |
在瀏覽器上的運行結果,此時兩個 this 會變相同:

這就是箭頭函式的特性,和箭頭函式中的 this 怎麼呼叫沒關係。而是類似 Scope(作用域)的機制,看程式碼定義在哪裡,就會利用定義的 block 來呈現這個 this 的值。
結語
瞭解到物件導向的相關概念後,接著要理解 this 是什麼就沒那麼困難了。或許是因為在實際學 JacaScript 以前,就預設 this 是很難是高手在用的東西,透過慢慢理解物件導向與 this 的關聯,以及如何判斷 this 的值,似乎也感覺到自己的進化,對於未知的恐懼總是需要克服的。
關於 this 的重點,就是記得 this 的值和程式碼在哪無關,而是和怎麼呼叫有關係。
總結前面提到的觀念,其實 this 大致可分成四種綁定方式:
- 默認綁定
在和物件導向無關的情況下,this 會被指定為全域物件。又依照執行環境不同,其值會是 global 或 window,而在嚴格模式下會是 undefined:
1 | function test() { |
- 隱式綁定
若在 function 中, this 有被某物件指定為屬性並呼叫,this 就是呼叫 function 的物件。以下方範例來說 this 就是 obj:
1 | function func() { |
- 顯示綁定
若是透過 .call()、.apply() 或 .bind() 方式指定 this,this 就會是傳入的參數:
1 | var obj = { |
- new 綁定
透過建構函式 new 出一個 instance,this 就會是 instance 物件本身:
1 | class Dog { |
- 例外:箭頭函式中的 this 是看程式碼定義在哪,和怎麼呼叫沒關係。
參考資料:
- 淺談 JavaScript 頭號難題 this:絕對不完整,但保證好懂
- 前端中階:JS令人搞不懂的地方-this
- JavaScript: Object-oriented JavaScript, Prototype Chain & This
- 關於this綁定的四種方式