箭头函数里的this到底指向谁?

  关于箭头函数里的this这个问题一直很模糊,之前看了很多教程虽然知道了其行为,但是具体实现规则一直不太清晰。今天为了彻底搞懂这个问题,查了很多资料,感觉查到的很多例子不是很能清晰的描述这种行为。所以今天特地自己写一遍文章来说明一下。

普通函数里的this

  先来说一下普通函数里的this。

1
2
3
4
5
var a = 1
function test() {
console.log(this.a) // this指向window,打印1
}
test()

  在普通函数里,this的值在定义时是不明确的,要等到调用时才能确定,谁调用就指向谁。上面代码里的test()是在全局作用域调用的,所以自然就指向window,控制台会打印1。

  再来看一个例子:

1
2
3
4
5
6
7
8
var a = 1
var obj = {
a: 2,
test: function() {
console.log(this.a)
}
}
obj.test() // 2

  上面的代码我们把test函数定义在里对象obj里,调用的时候是用obj来调用的,所以test函数里的this自然就指向obj,最后函数会打印2。

  再来看一个:

1
2
3
4
5
6
7
8
9
var a = 1
var obj = {
a: 2,
test: function () {
console.log(this.a)
}
}
var w = obj.test
w() // 1

  上面的代码我们把obj.test函数里的代码赋值给了一个全局变量w,然后用全局变量w调用了test函数,所以这里的this指向的也是window

  还有一种情况:

1
2
3
4
5
6
7
8
9
10
11
12
var a = 1
var obj = {
a: 2,
test: function () {
function fn() {
console.log(this.a)
}
return fn()
}
}

obj.test() // 1

  这里来看obj.test方法,这个方法里我们创建了一个fn函数,最后将fn函数的结果作为obj.test的结果返回,这里的fn是用return方法返回的,并没有被其它对象直接调用,普通函数里this也并不会被继承,所以这里的this指向全局的window

  setTimeout方法和setInterval方法中的this均指向window,如下:

1
2
3
4
5
6
7
8
9
10
11
var a = 1
var obj = {
a: 2,
test: function () {
setTimeout(function () {
console.log(this.a)
}, 1000)
}
}

obj.test() // 1

  上面的几种情况就是普通函数里this的指向。

  使用call()apply()bind()等方法可以手动改变普通函数里this的指向,在本文里就不详细叙述了。

箭头函数里的this

先说结论:

  • 箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this(结论出自MDN - 箭头函数
  • 使用call()、apply()、bind()等方法并不会直接修改箭头函数内的this
  • 箭头函数的this是在创建时就已经确定了
1
2
3
4
5
6
7
8
9
var a = 1
var obj = {
a: 2,
test: () => {
console.log(this.a)
}
}

obj.test() // 1

  这里的this是在箭头函数里的,所以会从自己的作用域链的上一层,也就是obj对象来继承this。最后一行obj是在全局中调用的,所以obj的this指向window,其结果打印的是1。

1
2
3
4
5
6
7
8
9
10
11
function a() {
function b() {
console.log(this === window) // true
var c = () => {
console.log(this) // window
}
return c()
}
return b()
}
a()

  上面的这个例子,c是箭头函数,所以c里的this继承自己的作用域链的上一层b,b是直接return返回的结果,this指向window。

  我们再把上面的例子修改一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var obj = {
a: 'xxx'
}

function a() {
function b() {
console.log(this === obj) // true
var c = () => {
console.log(this) // obj对象
}
return c()
}
b.call(obj)
}
a()

  上面的例子我们手动用call()方法把b的this指向更改为了obj,通过打印出来的结果再一次印证了箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this这一结论。

0%