前言
在 JavaScript 中,this是一个非常高频、也非常容易让人混乱的知识点。
很多初学者会发现:同样是一个函数,在不同场景下调用this的值居然不一样。
比如:
-
普通函数里的
this -
对象方法里的
this -
构造函数里的
this -
箭头函数里的
this -
call、apply、bind改变this指向
本文就来系统讲清楚:JavaScript 中 this 到底指向谁。
一、this 是什么?
this不是在函数定义时决定的,而是在函数调用时决定的。
也就是说:
谁调用这个函数,this 通常就指向谁。
先看一个简单例子:
const obj = {
name: 'Tom',
say() {
console.log(this.name);
}
};
obj.say(); // Tom
这里say()是被obj调用的,所以this指向obj。
二、普通函数中的 this
1)浏览器非严格模式下
function test() {
console.log(this);
}
test();
在浏览器非严格模式下,普通函数直接调用时,
this指向window。
2)严格模式下
'use strict';
function test() {
console.log(this);
}
test();
严格模式下,普通函数直接调用时,
this是undefined。
三、对象方法中的 this
如果函数作为对象的方法调用,那么this指向这个对象。
const obj = {
name: 'Alice',
say() {
console.log(this.name);
}
};
obj.say(); // Alice
注意,真正决定this的,不是函数写在哪,而是怎么调用。
const obj = {
name: 'Alice',
say() {
console.log(this.name);
}
};
const fn = obj.say;
fn(); // 浏览器非严格模式下通常是 undefined 或 window.name
这里fn()已经不是通过obj调用了,所以this不再指向obj。
四、构造函数中的 this
当函数通过new调用时,this指向新创建的实例对象。
function Person(name) {
this.name = name;
}
const p = new Person('Tom');
console.log(p.name); // Tom
这里this指向p。
五、箭头函数中的 this
箭头函数没有自己的this,它的this取决于外层作用域。
const obj = {
name: 'Tom',
say: () => {
console.log(this.name);
}
};
obj.say();
这里箭头函数不会绑定obj,而是继承外层的this
。
如果在浏览器全局环境下,通常指向window。
一个更容易理解的例子
const obj = {
name: 'Tom',
say() {
const fn = () => {
console.log(this.name);
};
fn();
}
};
obj.say(); // Tom
这里箭头函数fn继承了say()的this,也就是obj。
六、事件中的 this
在 DOM 事件中,普通函数里的this一般指向触发事件的元素。
button.onclick = function () {
console.log(this); // button 元素
};
如果写成箭头函数:
button.onclick = () => {
console.log(this);
};
那么这里的this不再指向按钮,而是继承外层作用域。
七、call、apply、bind 改变 this
JavaScript 提供了三种显式改变this的方法:
callapplybind
function say() {
console.log(this.name);
}
const obj = { name: 'Tom' };
say.call(obj); // Tom
say.apply(obj); // Tom
bind
不会立即执行,而是返回一个新的函数:
const fn = say.bind(obj);
fn(); // Tom
八、this 指向总结
可以简单记住下面几条:
-
普通函数直接调用:浏览器非严格模式下指向
window -
对象方法调用:指向调用它的对象
-
构造函数调用:指向新实例
-
箭头函数:没有自己的
this,继承外层 -
call/apply/bind:可以显式指定
this
九、总结
this的核心不是“函数定义在哪”,而是:
函数是如何被调用的。
只要抓住这句话,再结合几种常见场景,this就不会再那么抽象了。