箭头函数里的 this 到底指向谁?
关于箭头函数里的 this 这个问题一直很模糊,之前看了很多教程虽然知道了其行为,但是具体实现规则一直不太清晰。今天为了彻底搞懂这个问题,查了很多资料,感觉查到的很多例子不是很能清晰的描述这种行为。所以今天特地自己写一篇文章来说明一下。
普通函数里的 this
先来说一下普通函数里的 this。
1 | var a = 1 |
在普通函数里,this 的值在定义时是不明确的,要等到调用时才能确定,谁调用就指向谁。上面代码里的 test() 是在全局作用域调用的,所以自然就指向 window,控制台会打印 1。
再来看一个例子:
1 | var a = 1 |
上面的代码我们把 test 函数定义在对象 obj 里,调用的时候是用 obj 来调用的,所以 test 函数里的 this 自然就指向 obj,最后函数会打印 2。
再来看一个:
1 | var a = 1 |
上面的代码我们把 obj.test 函数里的代码赋值给了一个全局变量 w,然后用全局变量 w 调用了 test 函数,所以这里的 this 指向的也是 window。
还有一种情况:
1 | var a = 1 |
这里来看 obj.test 方法,这个方法里我们创建了一个 fn 函数,最后将 fn 函数的结果作为 obj.test 的结果返回,这里的 fn 是用 return 方法返回的,并没有被其它对象直接调用,普通函数里 this 也并不会被继承,所以这里的 this 指向全局的 window。
setTimeout 方法和 setInterval 方法中的 this 均指向 window,如下:
1 | var a = 1 |
上面的几种情况就是普通函数里 this 的指向。
使用 call()、apply()、bind() 等方法可以手动改变普通函数里 this 的指向,在本文里就不详细叙述了。
箭头函数里的 this
先说结论:
- 箭头函数不会创建自己的
this,它只会从自己的作用域链的上一层继承this(结论出自 MDN - 箭头函数) - 使用
call()、apply()、bind()等方法并不会直接修改箭头函数内的this - 箭头函数的
this是在创建时就已经确定了
1 | var a = 1 |
这里的 this 是在箭头函数里的,所以会从自己的作用域链的上一层,也就是 obj 对象来继承 this。最后一行 obj 是在全局中调用的,所以 obj 的 this 指向 window,其结果打印的是 1。
1 | function a() { |
上面的这个例子,c 是箭头函数,所以 c 里的 this 继承自己的作用域链的上一层 b,b 是直接 return 返回的结果,this 指向 window。
我们再把上面的例子修改一下:
1 | var obj = { |
上面的例子我们手动用 call() 方法把 b 的 this 指向更改为了 obj,通过打印出来的结果再一次印证了箭头函数不会创建自己的 this,它只会从自己的作用域链的上一层继承 this 这一结论。