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中文网其他相关文章!