在 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
是触发事件的元素,箭头函数除外。