这是《JavaScript的this机制与箭头函数》系列的第二篇文章,这里是系列的第一篇文章,主要讲解this的四种绑定机制,下面的内容会涉及到第一篇博文所讲解的部分知识点。
一开始接触箭头函数的时候就被其this的指向搞懵逼了,最后看了好多大牛的博客才搞清楚。
首先我们需要明白的是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this,这句话会解释箭头函数的很多行为——比如箭头函数不可以作为构造函数以及箭头函数不能使用call()、apply()、bind()这些方法去改变this的指向。
如何理解箭头函数“内部的this就是外层代码块的this”?举个栗子
var a=0;
function foo(){
function test(){
console.log(this.a);
}
return test;
}
var obj={
a : 2,
foo:foo
}
obj.foo()()//0
这里根据上一章所讲知识点——闭包中被返回到外部的函数也是独立调用,函数独立调用this指向window,所以这里的输出为0。
但当我们换为箭头函数后
var a=0;
function foo(){
console.log(this);
var test=()=>{
console.log(this.a);
}
return test;
}
var obj={
a : 2,
foo:foo
}
obj.foo()()
//输出对象obj
//输出2
这里可以发现test函数console出来的值为2,更进一步我们可以发现foo函数第一次console出来的this为对象obj。在上一章中我们知道函数采用方法调用时,this隐式绑定到该直接对象,所以会输出obj。而箭头函数中的this很明显就是对象obj,这就是所谓箭头函数“内部的this就是外层代码块的this”,即箭头函数的this就是其外层函数的this,而外部函数的this按照上一章this的四种绑定机制进行绑定,这样子就很容易判断出复杂嵌套函数里箭头函数this的指向了。
上面的箭头函数等价于这样子写
var a=0;
function foo(){
var that=this;
var test=()=>{
console.log(that.a);
}
return test;
}
var obj={
a : 2,
foo:foo
}
obj.foo()()
下面来看一个比较复杂的例子
function foo() {
setTimeout(function (){
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });
这里foo.call({ id: 42 });
是显示绑定,foo方法中的this应该指向对象{id:42},但setTimeout
是内置函数,其回调函数会发生隐式丢失,所以setTimeout中的this指向window。由于显示绑定不能解决隐式丢失问题,所以输出的id为21
但换用箭头函数之后
function foo() {
setTimeout(()=>{
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });
输出为42。这是因为使用箭头函数之后setTimeout中的this与外层函数foo的this一致,而foo.call({ id: 42 });
是显示绑定,foo方法中的this应该指向对象{id:42},所以输出42。
所以,处理箭头函数this指向时,只需要记住箭头函数的this与其外层函数this指向一致即可。