解釋 JavaScript 中 this 的值?

2022年10月9日

💎 加入 E+ 成長計畫 與超過 300+ 位軟體工程師一同在社群中成長,並且獲得更多的軟體工程學習資源

大部分 JavaScript 學習者在學習 this 概念時通常覺得一頭霧水,許多人覺得是 JavaScript 中最複雜的概念之一,然而 this 值是 JavaScript 面試經典題,搞懂 this 值也是戰勝面試的第一步。本篇文章會整理出來 this 值的 5 種判斷方式,讓讀者在面試時能輕易掌握這些概念。

在 JavaScript 中,this 的值是動態的,通常會由被呼叫的函式來決定。所以,影響 this 的值不是宣告的時機,關鍵在於在哪裡被調用。

this 值 5 種判斷方式

1. 函式調用

當一個函式不是屬於一個物件中的方法時,直接作為函式來調用時,this 會指向全局物件,在瀏覽器中,默認為 Window 。但有一點要注意的是,如果是在嚴格模式下,thisundefined

如下程式碼範例,因為是一般函式調用,this 會是指向 Window,所以第一個輸出結果是 Window。而因為在全域範圍中用 var 定義 name 變數,因此, name 變數也會綁定到 Window 物件上,第二個輸出結果也等同於 window.name 的值。(備註,如果是用 let 定義,並不會綁定在 Window 物件上。)

var name = "John";
function callThis() {
  console.log(this);
  console.log(this.name);
}
callThis();
// Window
// John

2. 物件方法調用

當一個函式是做為一個物件的方法來調用時,this 會指向這個物件。

const john = {
  name: "john",
  callJohn() {
    console.log(`hello, ${this.name}`);
  },
};

john.callJohn(); // hello, john

3. 構造函式調用

當一個函式用 new 關鍵字調用時,此函式執行前會先創造一個新的物件,this 會指向這個新組成的物件。

如下面程式碼例子所示,最後呼叫結果為 Apple 。這是因為當構造函式 Cellphonenew 調用時,會先創造一個新的物件,讓 this 會指向這個新物件,=在這個例子中,就印出了這個新物件的 brandApple

function Cellphone(brand) {
  this.brand = brand;
}

Cellphone.prototype.getBrand = function () {
  return this.brand;
};

let newIPhone = new Cellphone("Apple");
let newPixelPhone = new Cellphone("Google");

console.log(newIPhone.getBrand()); // Apple
console.log(newPixelPhone.getBrand()); // Google

4. apply、call、bind 方法調用

我們也可以使用 applycallbind 方法來指定 this 指向的物件。

  • apply 方法接受兩個參數,第一個是 this 綁定的對象,第二個會放入要傳入函式的陣列參數,並執行此新函式。
  • call 方法類似為 apply,唯一不同的地方是,apply 第二個參數是陣列,但 call 則是依序放在後面。
  • bind 方法透過傳入一個物件和要傳入的參數,不同於 applycallbind 不會立即執行此心函式,而是會返回此新函式。
function getBrand(prefix) {
  console.log(prefix + this.brand);
}

let apple = {
  brand: "Apple",
};
let sony = {
  brand: "Sony",
};

getBrand.call(apple, "It's a "); // It's a Apple
getBrand.call(sony, "It's an "); // It's an Sony

5. 箭頭函式中的 this

ES6 中介紹了一種新的函式型態 - 箭頭函式(arrow function)。但要注意的是,箭頭函式並沒有屬於自己的 this 值,箭頭函式的 this 會從他的外在函式繼承,若他的外在函式也同為箭頭函示,則回繼續往上尋找,直到找到全域環境的預設 this 值(例如:瀏覽器中就是 window)。

let getThis = () => this;
console.log(getThis() === window); // true
🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們