JavaScript this 是什麼?全域、事件監聽與箭頭函式
在 JavaScript 的世界中,this 的使用有些繁瑣,在這個章節 Away 會用幾個常見的狀態來說明。
先記住一句話:this 的值不是看它寫在哪裡,而是看函式被誰、以什麼方式呼叫。
全域環境
this 在全域的環境下運作會被當作全域物件,也就是 Window。
js
// Window
console.log(this);DOM 事件監聽
若 DOM 配合事件監聽器使用,this 會指向該 DOM。
html
<input id="Btn" type="button" value="mouseenter">js
document.querySelector('#Btn').addEventListener('mouseenter', function () {
// <input id="Btn" type="button" value="mouseenter">
console.log(this);
// Btn
console.log(this.id);
// button
console.log(this.type);
// mouseenter
console.log(this.value);
});承上,我們可以利用 this.value 來改變 value 屬性的文字內容。
js
document.querySelector('#Btn').addEventListener('mouseenter', function () {
this.value = 'mouseleave';
});
document.querySelector('#Btn').addEventListener('mouseleave', function () {
this.value = 'mouseenter';
});箭頭函式
箭頭函式是一個非常好用的功能,能讓程式碼寫起來更簡潔又快速,在使用上有些地方要特別留意。
js
document.querySelector('#Btn').addEventListener('mouseenter', () => {
// Window
console.log(this);
});TIP
- 箭頭函式沒有自己的
this。因此,在箭頭函式內使用this會指向最外層的Window。 - 承上,在 DOM 事件處理函式中,會找不到該 DOM 元素。因此,須改由 事件物件 來取得 DOM。
改寫成箭頭函式的版本,把 this 換成 e.currentTarget 就好:
js
document.querySelector('#Btn').addEventListener('mouseenter', (e) => {
e.currentTarget.value = 'mouseleave';
});三種情境速查
| 情境 | this 指向 |
|---|---|
| 全域(瀏覽器) | window |
| 一般函式的事件處理器 | 掛上監聽器的那個元素 |
| 箭頭函式 | 定義時外層作用域的 this,最外層即 window |
注意
一般函式被 單獨呼叫 時,非嚴格模式下 this 是 window,嚴格模式(含 ES 模組)下則是 undefined。這也是把方法從物件上取出來單獨呼叫後,this 就壞掉的原因。
實務上的建議
- 事件處理器要取得元素,優先用
e.currentTarget,它不受函式種類影響。 - 需要用
this取得元素時,函式定義 就別寫成箭頭函式。 - 同一支專案挑一種寫法貫徹到底,比記住所有規則更實際。
常見問題
this 的值是什麼時候決定的?
呼叫的那一刻。this 不看函式寫在哪裡,而看它被誰、以什麼方式呼叫,所以同一個函式在不同呼叫方式下 this 會不同。
為什麼箭頭函式裡的 this 不是那個元素?
因為箭頭函式沒有自己的 this,它沿用定義時外層作用域的 this。在瀏覽器最外層寫箭頭函式,this 就是 window,自然抓不到觸發事件的元素。
事件處理器該用一般函式還是箭頭函式?
都可以,重點是取得元素的方式要一致。用一般函式時可以用 this,用箭頭函式時改用事件物件的 currentTarget,寫法統一就不會踩雷。
this 與 event.currentTarget 一樣嗎?
在以一般函式撰寫的事件處理器中,兩者都指向掛監聽器的元素。差別是 currentTarget 不受函式種類影響,因此更好預測。
嚴格模式會影響 this 嗎?
會。一般函式被單獨呼叫時,非嚴格模式下 this 是 window,嚴格模式下則是 undefined。ES 模組預設就是嚴格模式。