描述
对于箭头函数中this的描述,主要有以下几种。
箭头函数不会创建this,它只会从自己作用域链的上一层继承this (出自MDN的解释)
箭头函数的this由它的外层(函数或全局)作用域来决定 (出自你不知道的JS P-99)
箭头函数体内的this就是定义时所在的对象,而非运行时所在的对象 (出自阮一峰 ES6标准入门 P-81)
所有的箭头函数都没有自己的this,指向外层 (出自github.com/ruanyf/es6t…)
下面我们通过几个典型的例子,对ES6 箭头函数中this指向进行分析,希望看完你会有收获。
demos
01. 定义在一个函数中,此时箭头函数中的this取决于外层函数中的this指向。
function foo() {
setTimeout(() => {
console.log(this);
}, 1000);
}
const obj = {};
foo(); // this === window
foo.call(obj); // this === obj
箭头函数定义在foo函数内, 它的作用域被包含在foo作用域和全局作用域中,根据上面描述的1、2、4条,我们都可以得出,这个箭头函数中的this,就是foo函数的this指向。
在全局作用域中调用foo, 写法上等同于window.foo(), 所以此时this指向的全局对象window
在obj上调用,此时foo中的this显式地绑定在obj对象上,所以this等于obj
02. 定义在一个对象中
对象的定义不会创建一个作用域。
var name = 'window';
const person1 = {
name: 'person1',
sayName: () => {
console.log(this.name);
}
}
person1.sayName(); // window
上面的代码运行结果是window,证明此时箭头函数中的this指向的是全局作用域window.
这里我们需要了解一下JS作用域了。
JS中存在基于函数的作用域,意味中每声明一个函数,都会为其自身创建一个气泡,而其他结构不会创建作用域气泡。(摘自 你不知道的JS P-22)
ps: JS中一共存在三种作用域,分别是全局作用域、函数作用域 和 块作用域。
从上面的描述,我们可以得出,上述代码其实一共存在两个作用域气泡。一个全局的作用域气泡和一个包含在其中的箭头函数的作用域气泡。根据一开始的描述,我们可以得出,箭头函数中的this是由外层作用域来决定,即全局作用域,所以此时this指向window.
==扩展:==
var name = 'window';
const person1 = {
name: 'person1',
obj: {
init: () => {
console.log(this.name);
}
}
}
person1.obj.init(); // window
有了上面对作用域的分析,此时再看这样的题,应该就不会被迷惑了。
03. 使用构造函数
有下面一段代码:
var name = "global";
function Person(name) {
this.name = name;
this.sayName = () => {
console.log(this.name)
}
}
const personA = new Person('aaa');
const personB = new Person('bbb');
personA.sayName(); // aaa
personB.sayName(); // bbb
JS具有基于函数的作用域,因此从代码来看,上面的代码包含了3个作用域,分别是全局作用域>>Person构造函数作用域>>箭头函数作用域。创建personA的时候,将构造函数的this指向了personA,由于该构造函数是箭头函数的上一层作用域,所以此时箭头函数中this指向personA。personB同理。
Ps: 这里将方法写在构造函数内,是不妥当的(详情请看关于JS对象创建)。这里我们只做代码的演示,便于我们更清楚的分析作用域。
==代码扩展01:==
// 在上面的基础上增加一句
PersonB.sayName.call(PersonA); // bbb
结果输出bbb, 证明在创建personB的时候,执行构造函数的代码,此时构造函数中的this指向了personB, 所以,此时箭头函数的this已经完成了绑定,并且在以后的过程中都不会再变。
==代码扩展02:==
这一段代码中,将箭头函数定义在原型对象上。
var name = "global";
function Person(name) {
this.name = name;
}
Person.prototype.sayName = () => {
console.log(this.name);
}
const personA = new Person('aaa');
const personB = new Person('bbb');
personA.sayName(); // global
personB.sayName(); // global
personB.sayName.call(personA); // global
从运行结果得知,不管是在personA、personB上调用sayName,最后得到的结果都是global. 证明箭头函数的this是继承自自己作用域链的上一层的this。(注:此时箭头函数的上一层是全局作用域)
结论
我们从多个方面,对箭头函数中的this指向做了代码的演示。
得出判断箭头函数中this指向最清晰、易懂的方式,就是对作用域的分析。
箭头函数的this,由它自己作用域的上一层作用域的this决定。
笔记中可能存在有误之处,欢迎指正。