JavaScript 中的 this

JavaScript 中的this关键字是一个非常有用的概念,但也是比较容易让人混淆的。 它和其他语言中使用的this或者self关键字有些不同。在 JavaScript 中,this指向的是当前调用函数的对象。这意味着相同的函数可能由不同的对象调用,并可能每次调用时都有不同的this值。

this 的指向方式

在 JavaScript 中,函数可以通过多种方式来调用,进而影响this的指向。以下是常见的情况及其指向:

  1. 全局对象中的函数调用——指向全局对象(浏览器中为 window)。
1
2
3
4
5
function myFunction() {
console.log(this); // 输出:Window {chrome:..., ...}
}

myFunction();
  1. 直接调用对象上的方法——指向该对象。
1
2
3
4
5
6
7
8
const obj = {
name: "Tom",
getName() {
console.log(this.name);
}
};

obj.getName(); // 输出:'Tom'
  1. 通过call()apply()或者bind()方法进行调用——指定的上下文对象。
1
2
3
4
5
6
7
const obj = { a: 1 };

function foo() {
console.log(this.a);
}

foo.call(obj); // 输出:1
  1. 构造函数中的new操作符——指向新创建的实例对象。
1
2
3
4
5
6
7
8
function Person(name, age) {
this.name = name;
this.age = age;
}

const person = new Person("Tom", 18);

console.log(person.name); // 输出:'Tom'

this 指向慎用

除了上述情况,有时由于作用域的影响,可能导致 this 指向不确定、错误或者不可预知。以下是一些需要特别注意的情况:

  • 在嵌套函数中,this的指向会发生变化。
1
2
3
4
5
6
7
8
9
10
11
const obj = {
name: "Tom",
func1() {
console.log(this.name); // 输出:Tom
function func2() {
console.log(this.name); // 输出:undefined
}
func2();
}
};
obj.func1();

在上面的例子中,func1()中的this指向obj,而在func2()中的this指向的是全局对象。

  • 当在闭包函数中引用this时,this也会被固定到当前函数的自由变量(closure variable)上下文上。
1
2
3
4
5
6
7
8
9
10
11
const obj = {
name: "Tom",
func() {
const self = this;
setTimeout(function () {
console.log(self.name);
}, 1000);
}
};

obj.func(); // 输出:'Tom'

在这个例子中,因为在 setTimeout 回调函数内部并没有bind()绑定或是使用箭头函数表达式,所以此时的this并不是obj对象,而是定时器本身的对象(即window)。我们解决方法是使用一个self变量先把this存起来,在回调函数中使用该变量备份的值。

  • 调用普通函数,this指向总是指向全局对象。
1
2
3
4
5
const obj = { name: "Tom" };
function func() {
console.log(this.name);
}
func(); // 输出:undefined

在上面的例子中,即使我们定义了obj对象和带有name属性的普通函数func(),但在直接调用该函数时,this指向的仍然是全局对象window。因此this.name输出的是undefined