首頁 >web前端 >js教程 >掌握 JavaScript 中的 &#this&# 關鍵字:不再回頭

掌握 JavaScript 中的 &#this&# 關鍵字:不再回頭

Susan Sarandon
Susan Sarandon原創
2025-01-06 06:59:40997瀏覽

Mastering the

JavaScript 的 this 關鍵字是一個基本概念,經常讓初學者和經驗豐富的開發人員感到困惑。如果不徹底理解它的動態性質,可能會導致意想不到的行為。本綜合指南旨在揭開這一點的神秘面紗,探索其各種背景、細微差別和最佳實踐,並附有說明性示例和具有挑戰性的問題,以鞏固您的理解。

對此的介紹

在 JavaScript 中,this 是一個關鍵字,引用目前程式碼正在執行的物件。與其他一些靜態綁定 this 的程式語言不同,JavaScript 的 this 是根據函數的呼叫方式動態決定的。

1. 全球背景

當不在任何函數內部時,this 指的是全域物件。

  • 在瀏覽器中:全域物件是window。
  • 在 Node.js 中: 全域物件是全域的。

範例

console.log(this === window); // true (in browser)
console.log(this === global); // true (in Node.js)

注意: 在嚴格模式下('use strict';),全域上下文中的 this 仍然是全域物件。

2. 函數上下文

一、常規功能

在常規函數中,這是由函數的呼叫方式決定的。

  • 預設綁定:如果在沒有任何上下文的情況下呼叫函數,則 this 會引用全域物件(或在嚴格模式下未定義)。

範例:

function showThis() {
  console.log(this);
}

showThis(); // Window object (in browser) or global (in Node.js)
  • 隱式綁定:當函數作為物件的方法被呼叫時,this 引用該物件。

範例

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

person.greet(); // "Hello, I'm Alice"

我們可以使用 callapplybind 明確設定它。

function greet() {
  console.log(`Hello, I'm ${this.name}`);
}

const person = { name: 'Bob' };
greet.call(person); // "Hello, I'm Bob"

二.箭頭功能

箭頭函數有一個詞法 this,這表示它們在創建時從周圍的作用域繼承了 this。

範例

const person = {
  name: 'Charlie',
  greet: () => {
    console.log(`Hello, I'm ${this.name}`);
  }
};

person.greet(); // "Hello, I'm undefined" (or global name if defined)

說明:由於箭頭函數沒有自己的this,所以this指的是全域對象,而不是person對象。

箭頭函數的正確用法:

const person = {
  name: 'Dana',
  greet: function() {
    const inner = () => {
      console.log(`Hello, I'm ${this.name}`);
    };
    inner();
  }
};

person.greet(); // "Hello, I'm Dana"

具有挑戰性的方面:如果將方法分配給變數並調用,則可能會失去其預期的上下文。
範例

const calculator = {
  value: 0,
  add: function(num) {
    this.value += num;
    return this.value;
  }
};

console.log(calculator.add(5)); // 5
console.log(calculator.add(10)); // 15

const addFunction = calculator.add;
console.log(addFunction(5)); // NaN (in non-strict mode, this.value is undefined + 5)

3.建構函數和this

當函數使用 new 關鍵字作為建構子時,this 指的是新建立的實例。

console.log(this === window); // true (in browser)
console.log(this === global); // true (in Node.js)

重要提示:
• 如果不使用new,this 可能會引用全域物件或在嚴格模式下未定義。
• 建構函數通常將第一個字母大寫,以區別於常規函數。

4. 事件處理程序中的 this

在事件處理程序中,這是指接收事件的元素。

範例

function showThis() {
  console.log(this);
}

showThis(); // Window object (in browser) or global (in Node.js)

5. 使用call、apply和bind進行明確綁定

JavaScript 提供了明確設定 this 值的方法:

  • call: 呼叫函數,並將其設定為第一個參數,後面跟著函數參數。
const person = {
  name: 'Alice',
  greet: function() {
    console.log(`Hello, I'm ${this.name}`);
  }
};

person.greet(); // "Hello, I'm Alice"
  • apply: 與 call 類似,但接受陣列形式的參數。
function greet() {
  console.log(`Hello, I'm ${this.name}`);
}

const person = { name: 'Bob' };
greet.call(person); // "Hello, I'm Bob"
  • bind: 傳回一個新函數,並將 this 綁定到第一個參數。
const person = {
  name: 'Charlie',
  greet: () => {
    console.log(`Hello, I'm ${this.name}`);
  }
};

person.greet(); // "Hello, I'm undefined" (or global name if defined)

用例:

  • 從其他物件借用方法。
  • 確保這在回調中保持一致。

6. 課堂上的 this

ES6 引入了類別,它為建構函數和方法提供了更清晰的語法。在類別方法中,this 指的是實例。
範例:

const person = {
  name: 'Dana',
  greet: function() {
    const inner = () => {
      console.log(`Hello, I'm ${this.name}`);
    };
    inner();
  }
};

person.greet(); // "Hello, I'm Dana"

類別中的箭頭函數:
箭頭函數可用於從類別上下文繼承 this 的方法,這對於回呼很有用。

const calculator = {
  value: 0,
  add: function(num) {
    this.value += num;
    return this.value;
  }
};

console.log(calculator.add(5)); // 5
console.log(calculator.add(10)); // 15

const addFunction = calculator.add;
console.log(addFunction(5)); // NaN (in non-strict mode, this.value is undefined + 5)

常見陷阱和最佳實踐

I. 失去這個背景

將方法作為回調時,原始上下文可能會遺失。
問題

function Person(name) {
  this.name = name;
}

const alice = new Person('Alice');
console.log(alice.name); // "Alice"


使用綁定來保留上下文。

<button>



<p><strong>Arrow Function Caveat:</strong><br>
Using arrow functions in event handlers can lead to this referring to the surrounding scope instead of the event target.<br>
<strong>Example:</strong><br>
</p>

<pre class="brush:php;toolbar:false">button.addEventListener('click', () => {
  console.log(this); // Global object or enclosing scope
});

二.錯誤使用箭頭函數

箭頭函數沒有自己的 this,這在用作方法時可能會導致意外的行為。

問題

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

const person = { name: 'Eve' };
greet.call(person, 'Hello'); // "Hello, I'm Eve"


使用常規函數作為物件方法。

greet.apply(person, ['Hi']); // "Hi, I'm Eve"

三.避免全局 this

無意中設定全域物件的屬性可能會導致錯誤。

問題

const boundGreet = greet.bind(person);
boundGreet('Hey'); // "Hey, I'm Eve"


使用嚴格模式或正確的綁定。

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

const dog = new Animal('Dog');
dog.speak(); // "Dog makes a noise."

先進理念

一、巢狀函數中的this

在巢狀函數中,this 可能不引用外部的 this。解決方案包括使用箭頭函數或將其儲存在變數中。
箭頭函數範例:

class Person {
  constructor(name) {
    this.name = name;
  }

  greet = () => {
    console.log(`Hello, I'm ${this.name}`);
  }
}

const john = new Person('John');
john.greet(); // "Hello, I'm John"

變數範例:

const obj = {
  name: 'Object',
  getName: function() {
    return this.name;
  }
};

const getName = obj.getName;
console.log(getName()); // undefined or global name

二.這與原型

使用原型時,這是指實例。

console.log(this === window); // true (in browser)
console.log(this === global); // true (in Node.js)

結論

JavaScript 中的 this 關鍵字是一個多功能且強大的功能,如果正確理解,可以大大增強您的編碼能力。


解決這個問題的 10 個棘手問題

為了真正鞏固您對此的理解,請解決以下具有挑戰性的問題。每個問題都旨在測試 JavaScript 中 this 關鍵字的不同面向和邊緣情況。解決方案在最後。

問題一:神秘的輸出

function showThis() {
  console.log(this);
}

showThis(); // Window object (in browser) or global (in Node.js)

問題 2:箭頭函數驚喜

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

person.greet(); // "Hello, I'm Alice"

問題 3:在回呼中綁定 this

function greet() {
  console.log(`Hello, I'm ${this.name}`);
}

const person = { name: 'Bob' };
greet.call(person); // "Hello, I'm Bob"

問題4:正確使用bind

const person = {
  name: 'Charlie',
  greet: () => {
    console.log(`Hello, I'm ${this.name}`);
  }
};

person.greet(); // "Hello, I'm undefined" (or global name if defined)

問題5:建構函數中的this

const person = {
  name: 'Dana',
  greet: function() {
    const inner = () => {
      console.log(`Hello, I'm ${this.name}`);
    };
    inner();
  }
};

person.greet(); // "Hello, I'm Dana"

問題 6:事件處理程序上下文

const calculator = {
  value: 0,
  add: function(num) {
    this.value += num;
    return this.value;
  }
};

console.log(calculator.add(5)); // 5
console.log(calculator.add(10)); // 15

const addFunction = calculator.add;
console.log(addFunction(5)); // NaN (in non-strict mode, this.value is undefined + 5)

問題 8:Promise 中的 this

function Person(name) {
  this.name = name;
}

const alice = new Person('Alice');
console.log(alice.name); // "Alice"

問題 9:用 bind 鏈接

<button>



<p><strong>Arrow Function Caveat:</strong><br>
Using arrow functions in event handlers can lead to this referring to the surrounding scope instead of the event target.<br>
<strong>Example:</strong><br>
</p>

<pre class="brush:php;toolbar:false">button.addEventListener('click', () => {
  console.log(this); // Global object or enclosing scope
});

問題 10:類別和繼承

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

const person = { name: 'Eve' };
greet.call(person, 'Hello'); // "Hello, I'm Eve"

棘手問題的解決方案

問題1的解決方案:

當 getName 被指派給變數並在沒有任何物件上下文的情況下呼叫時,這預設為全域物件。在非嚴格模式下,this.name指的是全域名稱,即'Global'。在嚴格模式下,這將是未定義的,從而導致錯誤。

greet.apply(person, ['Hi']); // "Hi, I'm Eve"

問題2的解決方案:

箭頭函數沒有自己的this;他們從周圍的範圍繼承它。在這種情況下,周圍的範圍是全域上下文,其中 this.name 是 'Global'。

const boundGreet = greet.bind(person);
boundGreet('Hey'); // "Hey, I'm Eve"

問題3的解決方案:

在 setInterval 回呼中,this 指的是全域物件(或在嚴格模式下未定義)。因此, this.seconds 要么增加 window.seconds 要么在嚴格模式下拋出錯誤。 timer.seconds 仍為 0。

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

const dog = new Animal('Dog');
dog.speak(); // "Dog makes a noise."

問題4的解決方案:

將retrieveX綁定到模組後,呼叫boundGetX()可以正確地將其設定為模組。

class Person {
  constructor(name) {
    this.name = name;
  }

  greet = () => {
    console.log(`Hello, I'm ${this.name}`);
  }
}

const john = new Person('John');
john.greet(); // "Hello, I'm John"

問題5的解決方案:

箭頭函數 getModel 從建構子繼承 this,它引用新建立的汽車實例。

const obj = {
  name: 'Object',
  getName: function() {
    return this.name;
  }
};

const getName = obj.getName;
console.log(getName()); // undefined or global name

問題6的解決方案:

在使用常規函數的事件處理程序中,this 指的是接收事件的 DOM 元素,即按鈕。由於按鈕沒有 name 屬性,因此 this.name 未定義。

console.log(this === window); // true (in browser)
console.log(this === global); // true (in Node.js)

問題7的解決方案:

  • 第一個console.log(this.name);裡面的outerFunc引用了obj,所以它印出'Outer'。
  • 第二個console.log(this.name);內部innerFunc引用全域對象,因此它在嚴格模式下列印'Global'或undefined。
function showThis() {
  console.log(this);
}

showThis(); // Window object (in browser) or global (in Node.js)

問題8的解決方案:

在 Promise 建構子中,this 指的是全域物件(或在嚴格模式下未定義)。因此, this.value 是未定義的(或在嚴格模式下導致錯誤)。

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

person.greet(); // "Hello, I'm Alice"

問題9的解決方案:

乘法函數與第一個參數 a 綁定為 2。當呼叫 double(5) 時,它有效地計算乘法(2, 5)。

function greet() {
  console.log(`Hello, I'm ${this.name}`);
}

const person = { name: 'Bob' };
greet.call(person); // "Hello, I'm Bob"

問題10的解決方案:

在Dog類別的speak方法中,setTimeout回呼是一個常規函數。因此,回呼中的 this 指的是全域對象,而不是狗實例。 this.name 為“未定義”,或如果未全域定義名稱,則會導致錯誤。

const person = {
  name: 'Charlie',
  greet: () => {
    console.log(`Hello, I'm ${this.name}`);
  }
};

person.greet(); // "Hello, I'm undefined" (or global name if defined)

要解決此問題,請使用箭頭函數:

const person = {
  name: 'Dana',
  greet: function() {
    const inner = () => {
      console.log(`Hello, I'm ${this.name}`);
    };
    inner();
  }
};

person.greet(); // "Hello, I'm Dana"

現在,它正確記錄了:

const calculator = {
  value: 0,
  add: function(num) {
    this.value += num;
    return this.value;
  }
};

console.log(calculator.add(5)); // 5
console.log(calculator.add(10)); // 15

const addFunction = calculator.add;
console.log(addFunction(5)); // NaN (in non-strict mode, this.value is undefined + 5)

以上是掌握 JavaScript 中的 &#this&# 關鍵字:不再回頭的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn