首先
箭头函数(Arrow Function)是 ECMAScript 6 中的新特性。
问题
从代码中分析箭头函数的指向问题:
function foo() {
return ()=>{
console.log(this.a)
}
}
const obj1 = {a:1}
const obj2 = {a:2}
const bar = foo.call(obj1)
bar.call(obj2)
我们将会看到哪一个 obj 的 a 会被打印出呢?
假如 foo 函数 return 的不是箭头函数而是传统的function,结果又是如何?
function foo() {
return function(){
console.log(this.a)
}
}
const obj1 = {a:1}
const obj2 = {a:2}
const bar = foo.call(obj1)
bar.call(obj2)
结果
箭头函数中,foo 外部函数首先绑定了 obj1,this 指向 obj1。由于箭头函数不更改 this 的指向, 所以内部函数 this 与外部函数的 this 一致。但内部函数再次绑定 obj2 使得 this 指向 obj2 了么? 并没有。因为箭头函数的 this 不是在运行的时候绑定的,而是在定义的时候绑定的, 指向词法作用域中的 this。
tips:
词法作用域(lexical scoping)也叫静态作用域。
Javascript 采用的就是词法作用域。
因为采用词法作用域,函数的作用域在函数定义的时候就决定了。
采用静态作用域时,会从内向外寻找变量。
所以箭头函数寻找 this 会从内向外寻找。
var x=1;
var obj={
x:2,
print: () => { // 箭头函数使用词法作用域寻找 this。 从内向外寻找 this, 这里一直找到全局变量, 所以 this.x 指向外部 x
console.log(this.x)
}
}
obj.print();
var x=1;
var obj={
x:2,
print: function() { // 普通函数根据 ‘执行上下文’
console.log(this.x)
}
}
obj.print();
var a = 1
var obj = {
a:2,
b:{
a:3,
c: {
a:4,
getA: ()=> { // 仍然找到全局变量
console.log(this.a)
}
}
}
}
obj.b.c.getA()
var a = 1
var obj = {
a:2,
b:{
a:3,
c: {
a:4,
getA: function() { // 执行时的上下文 this = c
// 箭头函数找到 this,也就是 c
return () => console.log(this.a)
}
}
}
}
obj.b.c.getA()()
所以,碰到箭头函数,我们根据词法作用域找 this,传统函数,我们根据执行上下文来判断 this 的指向。
再通俗一点, 传统函数,谁调用这个函数,this 就指向谁。(运行时确定)
而箭头函数的 this ,根据箭头函数定义的位置,从内向外查找到的第一个 this 就是它的 this。(定义时确定)