JavaScript 的 this 關鍵字是一個基本概念,經常讓初學者和經驗豐富的開發人員感到困惑。如果不徹底理解它的動態性質,可能會導致意想不到的行為。本綜合指南旨在揭開這一點的神秘面紗,探索其各種背景、細微差別和最佳實踐,並附有說明性示例和具有挑戰性的問題,以鞏固您的理解。
在 JavaScript 中,this 是一個關鍵字,引用目前程式碼正在執行的物件。與其他一些靜態綁定 this 的程式語言不同,JavaScript 的 this 是根據函數的呼叫方式動態決定的。
當不在任何函數內部時,this 指的是全域物件。
範例
console.log(this === window); // true (in browser) console.log(this === global); // true (in Node.js)
注意: 在嚴格模式下('use strict';),全域上下文中的 this 仍然是全域物件。
在常規函數中,這是由函數的呼叫方式決定的。
範例:
function showThis() { console.log(this); } showThis(); // Window object (in browser) or global (in Node.js)
範例
const person = { name: 'Alice', greet: function() { console.log(`Hello, I'm ${this.name}`); } }; person.greet(); // "Hello, I'm Alice"
我們可以使用 call、apply 或 bind 明確設定它。
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)
當函數使用 new 關鍵字作為建構子時,this 指的是新建立的實例。
console.log(this === window); // true (in browser) console.log(this === global); // true (in Node.js)
重要提示:
• 如果不使用new,this 可能會引用全域物件或在嚴格模式下未定義。
• 建構函數通常將第一個字母大寫,以區別於常規函數。
在事件處理程序中,這是指接收事件的元素。
範例
function showThis() { console.log(this); } showThis(); // Window object (in browser) or global (in Node.js)
JavaScript 提供了明確設定 this 值的方法:
const person = { name: 'Alice', greet: function() { console.log(`Hello, I'm ${this.name}`); } }; person.greet(); // "Hello, I'm Alice"
function greet() { console.log(`Hello, I'm ${this.name}`); } const person = { name: 'Bob' }; greet.call(person); // "Hello, I'm Bob"
const person = { name: 'Charlie', greet: () => { console.log(`Hello, I'm ${this.name}`); } }; person.greet(); // "Hello, I'm undefined" (or global name if defined)
用例:
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)
將方法作為回調時,原始上下文可能會遺失。
問題
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"
無意中設定全域物件的屬性可能會導致錯誤。
問題
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。解決方案包括使用箭頭函數或將其儲存在變數中。
箭頭函數範例:
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 關鍵字是一個多功能且強大的功能,如果正確理解,可以大大增強您的編碼能力。
為了真正鞏固您對此的理解,請解決以下具有挑戰性的問題。每個問題都旨在測試 JavaScript 中 this 關鍵字的不同面向和邊緣情況。解決方案在最後。
function showThis() { console.log(this); } showThis(); // Window object (in browser) or global (in Node.js)
const person = { name: 'Alice', greet: function() { console.log(`Hello, I'm ${this.name}`); } }; person.greet(); // "Hello, I'm Alice"
function greet() { console.log(`Hello, I'm ${this.name}`); } const person = { name: 'Bob' }; greet.call(person); // "Hello, I'm Bob"
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)
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 });
function greet(greeting) { console.log(`${greeting}, I'm ${this.name}`); } const person = { name: 'Eve' }; greet.call(person, 'Hello'); // "Hello, I'm Eve"
當 getName 被指派給變數並在沒有任何物件上下文的情況下呼叫時,這預設為全域物件。在非嚴格模式下,this.name指的是全域名稱,即'Global'。在嚴格模式下,這將是未定義的,從而導致錯誤。
greet.apply(person, ['Hi']); // "Hi, I'm Eve"
箭頭函數沒有自己的this;他們從周圍的範圍繼承它。在這種情況下,周圍的範圍是全域上下文,其中 this.name 是 'Global'。
const boundGreet = greet.bind(person); boundGreet('Hey'); // "Hey, I'm Eve"
在 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."
將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"
箭頭函數 getModel 從建構子繼承 this,它引用新建立的汽車實例。
const obj = { name: 'Object', getName: function() { return this.name; } }; const getName = obj.getName; console.log(getName()); // undefined or global name
在使用常規函數的事件處理程序中,this 指的是接收事件的 DOM 元素,即按鈕。由於按鈕沒有 name 屬性,因此 this.name 未定義。
console.log(this === window); // true (in browser) console.log(this === global); // true (in Node.js)
function showThis() { console.log(this); } showThis(); // Window object (in browser) or global (in Node.js)
在 Promise 建構子中,this 指的是全域物件(或在嚴格模式下未定義)。因此, this.value 是未定義的(或在嚴格模式下導致錯誤)。
const person = { name: 'Alice', greet: function() { console.log(`Hello, I'm ${this.name}`); } }; person.greet(); // "Hello, I'm Alice"
乘法函數與第一個參數 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"
在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中文網其他相關文章!