Skip to content

JavaScript this 是什麼?全域、事件監聽與箭頭函式

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

注意

一般函式被 單獨呼叫 時,非嚴格模式下 thiswindow,嚴格模式(含 ES 模組)下則是 undefined。這也是把方法從物件上取出來單獨呼叫後,this 就壞掉的原因。

實務上的建議

  • 事件處理器要取得元素,優先用 e.currentTarget,它不受函式種類影響。
  • 需要用 this 取得元素時,函式定義 就別寫成箭頭函式。
  • 同一支專案挑一種寫法貫徹到底,比記住所有規則更實際。

常見問題

this 的值是什麼時候決定的?

呼叫的那一刻。this 不看函式寫在哪裡,而看它被誰、以什麼方式呼叫,所以同一個函式在不同呼叫方式下 this 會不同。

為什麼箭頭函式裡的 this 不是那個元素?

因為箭頭函式沒有自己的 this,它沿用定義時外層作用域的 this。在瀏覽器最外層寫箭頭函式,this 就是 window,自然抓不到觸發事件的元素。

事件處理器該用一般函式還是箭頭函式?

都可以,重點是取得元素的方式要一致。用一般函式時可以用 this,用箭頭函式時改用事件物件的 currentTarget,寫法統一就不會踩雷。

this 與 event.currentTarget 一樣嗎?

在以一般函式撰寫的事件處理器中,兩者都指向掛監聽器的元素。差別是 currentTarget 不受函式種類影響,因此更好預測。

嚴格模式會影響 this 嗎?

會。一般函式被單獨呼叫時,非嚴格模式下 thiswindow,嚴格模式下則是 undefined。ES 模組預設就是嚴格模式。

延伸閱讀