這個 this 到底是什麼?
這個(this)到底是哪個?
基本上這個(this)脫離物件呼叫,就沒有太大的意義。
在 JavaScript 中,this
是一個經常讓人困惑的關鍵字,因為它的值在不同的情況下會有所變化。this
的值取決於函數的呼叫方式,而不是函數定義的地方。本文將介紹 this
在不同情況下的指向,並討論 call
、apply
、bind
這三種方法,以及如何解決 this
綁定的問題。
函數呼叫方式
在講解this
前,我們要先知道 function 在呼叫時,有幾種方法
- 作為函數去呼叫
- 作為方法去呼叫
- 作為建構式用
new
的方式呼叫 - 透過
apply
、call
的方式呼叫
1 | function sayByeBye(name) { |
一般情況下的 this
全域環境下的 this
在全域範圍中(非嚴格模式),this
指向全域物件(在瀏覽器中是 window
)。
例如:
1 | console.log(this); // 在瀏覽器中,輸出 window |
物件方法中的 this
當函數作為物件的方法呼叫時,this 指向該物件。例如:
1 | const obj = { |
在這裡,this
指向obj
,因此this.name
取到的是obj.name
。
獨立函數中的 this
當函數在全域範圍中獨立呼叫時,this
在非嚴格模式下會指向全域物件(瀏覽器中的window
)。在嚴格模式下,this
則會是undefined
。
1 | function showThis() { |
嚴格模式中的 this
在嚴格模式下,this
不再自動指向全域物件,如果函數獨立呼叫,this
會是undefined
。
1 | ; |
new 建構函數使用 this
當使用new
關鍵字來呼叫並建構函數時,this
的指向會有所不同。
new
會建立一個新的實體物件,並且this
會指向新創建的物件,而不是全域物件或其他任何物件。
1 | function Person(name) { |
使用箭頭函數的正確綁定在
introduceArrow
方法中,我們使用了箭頭函數。箭頭函數不會自己創建this
,而是從其外部環境繼承this
。在這裡,外部環境是Person
的實例,因此this
仍然指向Person
實例,能夠正確地存取 name 屬性。使用普通函數的錯誤綁定在
introduceRegular
方法中,我們使用了普通函數。這樣做會導致setTimeout
中的回調函數創建自己的this
,並且這個this
指向全域物件(在瀏覽器中為window
)或undefined
(在嚴格模式下)。
因此,當回調函數執行時,this.name
無法正確取得name
屬性,結果是undefined
。
修正錯誤綁定的方法
如果我們希望修正普通函數中的this
綁定,可以使用bind
方法或將回調函數改為箭頭函數。
使用bind
方法
1 | function Person(name) { |
使用箭頭函數
1 | function Person(name) { |
在以上修正方法中,bind
方法可以將this
繫結到指定的物件,而箭頭函數可以自動繼承外部環境中的this
。這樣可以確保在回調函數中,this
可以正確地指向實例對象。
call、apply 與 bind 解決 this 綁定
當我們希望手動指定this
的值時,可以使用call
、apply
或bind
。
每個 function 都會自帶這些方法可以呼叫直接呼叫使用。
call
call
方法允許我們明確地設定this
的值並立即執行該函數。它的語法是:
1 | function.call(thisArg, arg1, arg2, ...)。 |
第一個參數,就是我們要指定的this
1 | function introduce(greeting) { |
apply
apply
與call
類似,不同的是,apply
接受的是一個參數陣列而不是單獨的參數。
1 | function introduce(greeting) { |
apply
對於參數的傳遞方式更加靈活,尤其在參數數量不確定時。
bind
與call
和apply
不同的是,bind
並不會立即執行函數,它會返回一個新的函數,並將this
永遠綁定到指定的物件。
1 | function introduce(greeting) { |
常見問題與解決方法
問題:回調函數中的 this 不正確
在回調函數(例如事件處理器、setTimeout
)中,this
的值通常會出現問題,因為它可能會指向全域物件或undefined
。解決這個問題的方法包括使用bind
或箭頭函數。
使用bind
1 | const button = document.getElementById('myButton'); |
使用箭頭函數
箭頭函數不會自己綁定this
,而是繼承外部環境中的this
。
1 | const obj = { |
範例
1 | const obj = { |