在 JavaScript 中,this 的指向是动态的,取决于函数的调用方式。以下是几种常见情况下 this 的指向规则:
全局作用域
在 非严格模式下,this 指向全局对象(浏览器中是 window,Node.js 中是 global)。
在 严格模式下,this 为 undefined。
// 非严格模式
console.log(this); // window(浏览器中)
// 严格模式
"use strict";
console.log(this); // undefined
普通函数调用
无论函数是在哪里定义的,直接调用函数时,this 指向 全局对象(非严格模式)或 undefined(严格模式)。
function sayHello() {
console.log(this);
}
sayHello(); // window(非严格模式)或 undefined(严格模式)
对象方法调用
当函数作为对象的方法调用时,this 指向调用该方法的 对象本身。
const obj = {
name: "Object",
sayName: function () {
console.log(this.name);
}
};
obj.sayName(); // 输出 "Object"
需要注意的是如果把方法赋值给一个变量,this 会变成全局对象或 undefined(取决于是否严格模式)。
const obj = {
name: "Object",
sayName: function () {
console.log(this.name);
}
};
const func = obj.sayName;
func(); // undefined(因为此时丢失了调用的上下文)
构造函数调用
使用 new 调用构造函数时,this 指向新创建的对象。
function Person(name) {
this.name = name;
}
const p = new Person("Alice");
console.log(p.name); // 输出 "Alice"
箭头函数
箭头函数的 this 是在函数定义时确定的,继承自其定义时的外层作用域的 this,并且不会因为调用方式改变。
const obj = {
name: "Object",
sayName: () => {
console.log(this.name);
}
};
obj.sayName(); // undefined(箭头函数的 this 指向外层作用域,这里是全局)
比较常见的在事件监听器或回调中使用箭头函数,避免 this 指向问题。
function Timer() {
this.seconds = 0;
setInterval(() => {
this.seconds++;
console.log(this.seconds); // 正确指向 Timer 的实例
}, 1000);
}
new Timer();
显式绑定
使用 call、apply、bind 可以显式指定 this 的指向。
call 和 apply 两者都立即调用函数,区别在于参数传递方式:
call:逐个传递参数。apply:以数组形式传递参数。
function greet(greeting, punctuation) {
console.log(greeting + " " + this.name + punctuation);
}
const person = { name: "Alice" };
greet.call(person, "Hello", "!"); // 输出 "Hello Alice!"
greet.apply(person, ["Hi", "."]); // 输出 "Hi Alice."
bind:返回一个绑定了 this 的新函数,不会立即调用。
const person = { name: "Alice" };
const greetBound = greet.bind(person, "Hey");
greetBound("!"); // 输出 "Hey Alice!"
事件监听器
在事件监听器中,this 默认指向触发事件的元素。
const button = document.querySelector("button");
button.addEventListener("click", function () {
console.log(this); // 输出 <button> 元素
});
需要注意的是使用箭头函数会改变 this 的指向,使其指向外层作用域。
button.addEventListener("click", () => {
console.log(this); // 输出 window(箭头函数继承外层作用域的 this)
});
类的方法
在类中,普通方法的 this 指向调用它的对象实例。
class Person {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
const person = new Person("Alice");
person.sayName(); // 输出 "Alice"
需要注意的是 如果将类方法作为回调函数使用,可能会丢失 this。解决方法:
- 使用箭头函数。
- 手动绑定
this。
class Person {
constructor(name) {
this.name = name;
}
sayName = () => {
console.log(this.name);
};
}
const person = new Person("Alice");
const func = person.sayName;
func(); // 输出 "Alice"
总结规则
- 默认规则:直接调用函数时,
this是全局对象或undefined(严格模式)。 - 对象方法:
this是调用方法的对象。 - 构造函数:
this是新创建的对象。 - 箭头函数:
this是定义时的外层作用域。 - 显式绑定:用
call、apply、bind指定this。 - 事件监听器:
this是触发事件的元素,箭头函数除外。