浅析ES6箭头函数的this绑定是声明时绑定的还是运行时确定的
ES6都用了这么久了,我们都知道箭头函数没有 this,但是正好昨天做项目的时候纠结了一下这个问题,网上找了几篇排名比较靠前的文章,但都没有完全理解,或者说总觉得文章的说法并不完全正确。所以想要自己去实践一下得到自己的理解。
先来看看MDN怎么说: 箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。就这么简单的一句话,其实已经把箭头函数的this指向完全解释清楚了。
一、示例理解
我们看一下这下面的 3 个示例:
const obj = {
a: () => {
console.log(this)
}
}
obj.a()
// 结果为window,很好理解,例子中只有两个作用域,全局作用域和箭头函数自己的作用域,按照定义,它的作用域链上一层就是window
const obj = {
a: function () {
console.log(this)
}
}
obj.a()
// 结果为 obj,也好理解,obj调用的
const obj = {
b: this,
a: {
c: this
}
}
obj.b // window
obj.a.c // window
所以最近的 this 指向就是 window。再看这个示例,箭头函数的 this 不会被 call 之类的影响
var foo = () => {
console.log(this, this.a)
}
var obj = { a: 2 }
foo.call(obj) // undefined this为window
那么再看下面这个例子
function foo() {
return () => {
console.log(this.a);
}
}
var obj1 = { a:2 };
var obj2 = { a:3 };
foo()() // undefined this为window
foo.call(obj1)() // 2 this为obj1
foo.call(obj2)() // 3 this为obj2
为什么从这个示例看,好像箭头函数的 this 被 call 影响到了呢?
二、深入理解
简单总结一下:
1、箭头函数作为函数的一种形式,对于this的处理和普通函数有所区别,其没有自己的this上下文,也就是说通过bind/call/apply函数方法设置this值时无效的,会被忽略
2、因为箭头函数没有自己的this上下文,那么当它作为对象的方法函数运行时,this并不指向这个对象
3、箭头函数的的函数体中出现的this在运行时绑定到最近的作用域上下文对象
4、你可以认为箭头函数的this和调用者无关,只和其定义时所在的上下文相关
我们看一下 es6 的箭头函数转换成 es5 是怎样的?实际上它就是在最近的上一层作用域里做了一次this重定向
他把这个 this 提到了上一层,然后做了一个 this 重定向的操作
运行 obj.a 箭头函数时,将会查找this绑定的上下文对象:如果obj定义在一个函数体内,那么这个this就绑定到这个函数体对应的this对象上;如果定义在一个全局作用域下,那么就绑定到全局window对象上(浏览器环境下)
可以看到它就是通过这种 this 重定向的方式去从自己作用域链的上一层去继承this的
function objWrapper(){
var a=10;
var obj = {
foo: () => console.log(this.a)
};
obj.foo();
}
objWrapper.call({a:20});//20
objWrapper();//undefined
所以需要注意的就是指向静态,并不代表值是静态的。
那么回到标题的问题?箭头函数的 this 是声明时绑定的,还是运行时确定的呢?
声明时绑定的意思是它要确定到其上一层去做一个 this 重定向的处理。运行时确定是指其上一层的 this 是受运行时调用者影响的,那么箭头函数继承至该 this,自然也会受到影响。
也就是说:声明时确定继承自谁的 this、运行时真正确定是哪个 this