箭头函数的作用域和this
JS里的作用域和this一直是一件令人头疼的事情,以前接触的不太多,毕竟面向过程编程的我基本上都不会使用“类”这个概念。
自从开始学习ES6,很长一段时间都认为箭头函数(Arrow Function)^1就是给懒人用的简写的匿名函数而已。后来看到有人挑战阮一峰老师《ECMAScript 6入门》中关于箭头函数this的一些问题^2,才对箭头函数有了一丁点的理解。
我平时的工作基本上都是各种第三方的API整合,于是各种异步请求,promise都是家常便饭。由于SalesForce没有直接的nodejs sdk,所以自己写一个自定义的类就不可避免了。在写的过程中,关于this踩到坑里了,所以就有了这篇文章。
场景
其中一个简单的功能是,查找用户是否存在,若存在则发送欢迎邮件(整个流程对应onBoardFlow
)。实际场景比这个要复杂,可能需要连续发送好几个请求,为了避免回调地狱,所有的请求我都用promise包了起来。
1 | 'use strict'; |
方案
在onBoardFlow
中,搞不清this和作用域的我首先这么写:1
2//例1
this.checkuser().then(this.sendEmail); //Cannot read property 'email' of undefined
然后想到了在promise链中,this指向的是global;
Q: 为什么能找到
this.sendEmail()
方法,却找不到this.email
属性呢?
A: 我的理解是:因为this.sendEmail
是作为参数传入,传入的this是then外部的this,也就是SalesForce
对象;
而this.sendEmail函数的作用域中产生了新的this,而这个this指向global(浏览器中为window对象);在严格模式下this为undefined;
然后容易想到的就是各种_this self,然后bind(this) call(_this)之类的1
2//例2
this.checkuser().then(this.sendEmail.bind(this)); //it works !
这样是可以正常工作的,但感觉怪怪的,每个then都要bind(this)
真是一点也不优雅。
匿名函数和箭头函数原来不一样啊1
2
3
4//例3
this.checkuser().then(function(){
return this.sendEmail();
}); //Cannot read property 'updateFunnelData' of undefined
此时this.sendEmail
的this是then中的匿名函数新产生的promise作用域下的this,非严格模式下指向global
在箭头函数出现之前,每个新定义的函数都将新产生自己作用域下的this, arguments等对象^1
1 | 例4 |
词法作用域
作用域内可以嵌套作用域,从而形成作用域链,在最外层的也就是全局作用域,当在内部查找一个对象时,会顺着作用域链最内层,层层向外寻找,直到找到为止。
在例3中,匿名函数的作用域中产生了新的this
,该this
指向global
在例4中,箭头函数的作用域中没有产生新的this,所以顺着作用域链层层往外寻找this
,找到onBoardFlow()
的作用域时,找到了this
,而此时this
就是SalesForce
对象
为什么promise中的this指向global
这个,我还没学会…