跳至主要内容

1 篇文章 含有標籤「this」

檢視所有標籤

深入解析 JavaScript this - 用 apply、call 和 bind 克服函式綁定挑戰

· 閱讀時間約 5 分鐘

在 JavaScript 中,this 的值取決於函式的呼叫上下文,而不是函式的定義位置。這使得 this 的行為有時候很難預測和控制。

首先我們先來複習一下 JavaScript 中 this 的行為:

this

在 JavaScript 中,this 是一個很特別的關鍵字,它的值會根據它所在的環境而改變。簡單來說,this 指的是呼叫函式時的上下文(context),也就是「誰」在呼叫這個函式。

傳統函式中的 this

在傳統函式裡,this 的指向取決於函式是**「怎麼」被呼叫的**

const person = {
name: "Alice",
greet: function () {
console.log(`Hi, I'm ${this.name}`);
},
};

// 這個 greet 函式是透過 person 物件來呼叫的。
// 這意味著,JavaScript 會把 this 綁定到 person,讓 this.name 指向 person.name。
person.greet(); // Hi, I'm Alice

const greetFunction = person.greet;
// 這裡的 this 就指向 window 物件,因為 greetFunction 是直接被呼叫的。
// 這時候 this.name 就會是 undefined 或 window.name 的值。
greetFunction(); // Hi, I'm

箭頭函式中的 this

箭頭函式的 this 行為可以理解為**「綁定」到箭頭函式定義時的詞法環境 (Lexical Environment)**,而不是函式被呼叫時的上下文。

const person = {
name: "Alice",
greet: () => {
console.log(`Hi, I'm ${this.name}`);
},
greet1: function () {
// 這裡的箭頭函式會繼承外層的 this,這個 this 是指向 person
const innerGreet = () => {
console.log(`Hi, I'm ${this.name}`); // 這裡的 this 指向 person
};
innerGreet();
},
};

// 這裡的 this 指向的是全域對象,而不是 person 物件
// person 物件並不是 greet 函式的外層上下文;this 的繼承來源是 greet 函式的定義上下文
person.greet(); // Hi, I'm

person.greet1(); // Hi, I'm Alice

this 的難題主要來自於它的綁定方式,這使得 this 的行為有時候很難預測和控制。 要解決 this 的問題,我們可以使用 Function.prototype.bindcallapply 方法

Function.prototype.bind

Function.prototype.bind 方法可以用來永久地綁定函式的 this 值,並回傳一個新的函式

const person = {
name: "Alice",
greet: function () {
console.log(`Hello, ${this.name}`);
},
};

const greet = person.greet;
greet(); // 輸出 'Hello, undefined',因為 this 指向了全域物件

const boundGreet = person.greet.bind(person);
boundGreet(); // 輸出 'Hello, Alice',因為 this 被綁定到 person

Function.prototype.call 和 Function.prototype.apply

Function.prototype.callFunction.prototype.apply 方法可以用來臨時地綁定函式的 this 值,並立即執行這個函式

callapply 的差別在於傳入參數的方式,call逐個傳入,而 apply以陣列的方式傳入

const person = {
name: "Alice",
};

function greet(greeting) {
console.log(`${greeting}, ${this.name}`);
}

greet.call(person, "Hello"); // 輸出 'Hello, Alice'
greet.apply(person, ["Hi"]); // 輸出 'Hi, Alice'

總結

  1. bind():用於創建一個新的函式,這個函式的 this 被固定為指定的物件。適用於需要保證 this 的綁定時機的情境,例如回調函式。
  2. call()apply():用於立即呼叫函式並指定 this 的值。call() 用逗號分隔的參數,apply() 用數組分隔的參數。
  3. 箭頭函式:箭頭函式的 this 是從函式定義時的詞法環境繼承的,適合在函式內部使用時保證 this 的一致性。

這些方法可以幫助你更好地控制和理解 this 的行為,使你的 JavaScript 程式碼更易於維護和預測。