add by zhj: 最近在看ES6,看到了箭头函数,我我的感受箭头函数适用于函数体中不用this的匿名函数,在箭头函数中使用this是一个坑node
原文:http://ourjs.com/detail/584f83664edfe07ccdb23445程序员
在ES6大行其道的今天,不该用点ES6特性彷佛有些政治不正确。最近恰好有个Node的项目,最低要支持到nodejs 4.0,在node.green看了下ES6的支持度,我想使用的特性基本都有支持,遂决定在新项目中采用ES6来写。编程
固然第一件事情就是绝不留情地消灭var,项目中能用const的地方不用let,能用let的地方不用var。闭包
第二件事情就是使用劳动人民喜闻乐见的箭头函数替代function。当我心满意足地看到满屏的=>
时,现实给了我一记响亮的耳光——改过以后的程序错误百出!编程语言
因此,当咱们使用箭头函数时,必定要搞清楚箭头函数是什么回事,适用于什么场景。本文就针对以上问题来讨论下箭头函数。函数式编程
箭头函数的语法我就不讲了,相信你们都见识过。跟我同样,你们喜欢箭头函数90%的缘由是它好看。除了好看,它是否是与function等价呢?确定不等价,由于TC39不可能仅由于好看而引入一个语法糖(class除外)。函数
箭头函数的渊源能够追溯到上古时期一个叫lambda演算的东西。lambda演算是数学家提出来的,有些数学家跟咱们程序员同样也很懒,数学定理那么多,今天要证三角定律,明天要证勾股定律,累不累!那能不能将全部的证实问题用一个统一的体系进行形式化描述,而后由机器来完成自动推导呢?lambda演算就是干这个的,图灵也搞了一套体系叫图灵机,二者是等价的。this
关于lambda演算说了这么多,好像跟今天要讲的箭头函数没什么关系?实际上是有关系的,lambda演算深入影响了箭头函数的设计。数学家们喜欢用纯函数式编程语言,纯函数的特色是没有反作用,给予特定的输入,老是产生肯定的输出,甚至有些状况下经过输出可以反推输入。要实现纯函数,必须使函数的执行过程不依赖于任何外部状态,整个函数就像一个数学公式,给定一套输入参数,不论是在地球上仍是火星上执行都是同一个结果。spa
箭头函数要实现相似纯函数的效果,必须剔除外部状态。因此当你定义一个箭头函数,在普通函数里常见的this
、arguments
、caller
是通通没有的。prototype
this
箭头函数没有this
,那下面的代码明显能够取到this
啊:
function foo() { this.a = 1 let b = () => console.log(this.a) b() } foo() // 1
以上箭头函数中的this
实际上是父级做用域中的this
,即函数foo
的this
。箭头函数引用了父级的变量,构成了一个闭包。以上代码等价于:
function foo() { this.a = 1 let self = this let b = () => console.log(self.a) b() } foo() // 1
箭头函数不只没有this
,经常使用的arguments
也没有。若是你能获取到arguments
,那它必定是来自父做用域的。
function foo() { return () => console.log(arguments[0]) } foo(1, 2)(3, 4) // 1
上例中若是箭头函数有arguments
,就应该输出的是3而不是1。
一个常常犯的错误是使用箭头函数定义对象的方法,如:
let a = { foo: 1, bar: () => console.log(this.foo) } a.bar() //undefined
以上代码中,箭头函数中的this
并非指向a
这个对象。对象a
并不能构成一个做用域,因此再往上到达全局做用域,this
就指向全局做用域。若是咱们使用普通函数的定义方法,输出结果就符合预期,这是由于a.bar()
函数执行时做用域绑定到了a
对象。
let a = { foo: 1, bar: function() { console.log(this.foo) } } a.bar() // 1
另外一个错误是在原型上使用箭头函数,如:
function A() { this.foo = 1 } A.prototype.bar = () => console.log(this.foo) let a = new A() a.bar() //undefined
一样,箭头函数中的this
不是指向A
,而是根据变量查找规则回溯到了全局做用域。一样,使用普通函数就不存在问题。
经过以上说明,咱们能够看出,箭头函数除了传入的参数以外,真的是什么都没有!若是你在箭头函数引用了this
、arguments
或者参数以外的变量,那它们必定不是箭头函数自己包含的,而是从父级做用域继承的。
到这里,咱们能够发现箭头函数并非万金油,稍不留神就会踩坑。
至于什么状况该使用箭头函数,《You Don’t Know JS》给出了一个决策图:
以上决策图看起来有点复杂,我认为有三点比较重要:
map
、reduce
、filter
的回调函数定义中;this
会很容易污染全局做用域。最起码在箭头函数外部包一层普通函数,将this
控制在可见的范围内;