在大多数面向对象语言中,this
表示当前对象的一个引用,而 JS 中的 this
是完全不同的概念。
我们查阅 MDN 文档可知,this
是当前执行上下文(global
、function
或 eval
)的一个属性。
也就是说,我们可以把 JS 中的 this
分为三种,分别是:
- 全局上下文中的
this
。 - 函数上下文中的
this
。 eval
上下文中的this
。
关于 eval ,在 MDN 或很多书籍和文档中都建议永远不要使用它,我们就不讨论它了,接下来,我们将主要讨论全局上下文和函数上下文的 this
。
有一点需要注意的是,node
环境中的 this
和 web
环境中的 this
是不同的,为了避免大家一开始接受太多概念,我们先只讨论 web
环境的 this
。
全局上下文的 this
全局上下文的 this
指向非常明确,不管有没有启用严格模式,都指向 window
对象。
给 this
添加属性,就相当于给 window
添加属性,给 window
添加属性,就相当于给 this
添加属性,如下代码所示
this.userName = "zhangsan";
window.age = 18;
console.log(this.age); // 输出 18
console.log(window.userName); // 输出 'zhangsan'
函数上下文的 this
全局上下文的 this
很简单,记住无脑指向 window
就完事,复杂就复杂在函数上下文的 this
,函数上下文中的 this
与 arguments
一样,就是函数的隐式参数,可以在任意函数中调用,它的指向不是固定不变的,取决于函数处于什么位置、以什么方式调用,可以总结成如下图:
全局上下文中的函数
直接调用全局上下文中的函数,this
指向默认情况下为 window
。
function fn() {
let a = 1;
console.log(this.a); // 输出 2
}
var a = 2;
fn();
但是在严格模式下,this
指向的就是 undefined
。
function fn() {
"use strict";
console.log(this); // 输出 undefined
}
fn();
对象中的函数
调用对象中的函数,this
指向为这个对象。
const obj = {
a: 1,
fn() {
console.log("this :>> ", this); // 输出 obj
console.log("this.a :>> ", this.a); // 输出 1
},
};
obj.fn();
但是如果函数嵌套有函数,此时的 this
指向为 window
,就非常令人迷惑。
const obj = {
a: 1,
fn() {
return function () {
console.log("this :>> ", this); // 输出 window
console.log("this.a :>> ", this.a); // 输出 100
};
},
};
var a = 100;
obj.fn()();
其实可以这么理解
obj.fn()();
等价于;
const temp = obj.fn(); // 定义一个临时变量来存储 obj.fn 返回的函数
temp(); // 执行这个函数
上面代码示例中的 temp
在运行时是处在 window
环境中的,所以 this
指向 window
。
箭头函数
遇到对象里有函数嵌套函数的情况,想要 this
指向这个对象,es6 之前,可以用一个临时变量 _this
来暂存 this
,代码如下:
const obj = {
a: 1,
fn() {
const _this = this;
return function () {
console.log("this :>> ", _this); // 输出 obj
console.log("this.a :>> ", _this.a); // 输出 1
};
},
};
obj.fn()();
es6 推出了箭头函数的概念,之后我们就可以使用箭头函数解决这个问题,代码如下:
const obj = {
a: 1,
fn() {
return () => {
console.log("this :>> ", this); // 输出 obj
console.log("this.a :>> ", this.a); // 输出 1
};
},
};
obj.fn()();
对于普通函数来说,内部的 this
指向函数运行时所在的对象。
对于箭头函数,它不会创建自己的 this
,它只会从自己的作用域链的上一层继承 this。
所以这里 fn
中嵌套的匿名箭头函数中的 this
,指向它作用域链的上一层的 this
,也就是函数 fn
的 this
,也就是 obj
。
构造函数
构造函数内,如果返回值是一个对象,this
指向这个对象,否则 this
指向新建的实例。
function Person(name) {
this.name = name;
}
const p = new Person("zhangsan");
console.log(p.name); // 'zhangsan'
function Person(name) {
this.name = name;
return {
name: "xxx",
};
}
const p = new Person("zhangsan");
console.log(p.name); // 'xxx'
如果有返回值,但是不是一个对象,this
还是指向实例。
function Person(name) {
this.name = name;
return 123;
}
const p = new Person("zhangsan");
console.log(p.name); // 'zhangsan'