OurJS


OurJS-我们的JS, 我们的技术-IT文摘; 专注JS相关领域;
我们热爱编程, 我们热爱技术;我们是高大上, 有品味的码农;

欢迎您订阅我们的技术周刊


我们会向您分享我们精心收集整理的,最新的行业资讯,技术动态,外文翻译,热点文章;
我们使用第三方邮件列表向您推送,我们不保存您的任何个人资料,注重您的隐私,您可以随时退订,

欢迎分享您的观点,经验,技巧,心得

让我们一起找寻程序员的快乐,探索技术, 发现IT人生的乐趣;


本网站使用缓存技术每次加载仅需很小流量, 可在手机中流畅浏览;
如果您发现任何BUG,请即时告知我们: ourjs(at)ourjs.com

少年,不要滥用箭头函数啊:JS中lambda表达式的优缺点和使用场景


分享到
分类 JS学习   关键字 JavaScript   发布 ourjs  1481605990996
注意 转载须保留原文链接,译文链接,作者译者等信息。  

在ES6大行其道的今天,不应用点ES6特性似乎有些政治不正确。最近刚好有个Node的项目,最低要支持到nodejs 4.0,在node.green看了下ES6的支持度,我想使用的特性基本都有支持,遂决定在新项目中采用ES6来写。

当然第一件事情就是毫不留情地消灭var,项目中能用const的地方不用let,能用let的地方不用var。

第二件事情就是使用劳动人民喜闻乐见的箭头函数替代function。当我心满意足地看到满屏的=>时,现实给了我一记响亮的耳光——改过之后的程序错误百出!

所以,当我们使用箭头函数时,一定要搞清楚箭头函数是什么回事,适用于什么场景。本文就针对以上问题来讨论下箭头函数。

箭头函数是什么?

箭头函数的语法我就不讲了,相信大家都见识过。跟我一样,大家喜欢箭头函数90%的原因是它好看。除了好看,它是不是与function等价呢?肯定不等价,因为TC39不可能仅因为好看而引入一个语法糖(class除外)。

箭头函数的渊源可以追溯到上古时期一个叫lambda演算的东西。lambda演算是数学家提出来的,有些数学家跟我们程序员一样也很懒,数学定理那么多,今天要证三角定律,明天要证勾股定律,累不累!那能不能将所有的证明问题用一个统一的体系进行形式化描述,然后由机器来完成自动推导呢?lambda演算就是干这个的,图灵也搞了一套体系叫图灵机,两者是等价的。

关于lambda演算说了这么多,好像跟今天要讲的箭头函数没什么关系?其实是有关系的,lambda演算深刻影响了箭头函数的设计。数学家们喜欢用纯函数式编程语言,纯函数的特点是没有副作用,给予特定的输入,总是产生确定的输出,甚至有些情况下通过输出能够反推输入。要实现纯函数,必须使函数的执行过程不依赖于任何外部状态,整个函数就像一个数学公式,给定一套输入参数,不管是在地球上还是火星上执行都是同一个结果。

箭头函数要实现类似纯函数的效果,必须剔除外部状态。所以当你定义一个箭头函数,在普通函数里常见的thisargumentscaller是统统没有的。

箭头函数没有this

箭头函数没有this,那下面的代码明显可以取到this啊:

function foo() {
  this.a = 1
  let b = () => console.log(this.a)

  b()
}

foo()  // 1

以上箭头函数中的this其实是父级作用域中的this,即函数foothis。箭头函数引用了父级的变量,构成了一个闭包。以上代码等价于:

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,而是根据变量查找规则回溯到了全局作用域。同样,使用普通函数就不存在问题。

通过以上说明,我们可以看出,箭头函数除了传入的参数之外,真的是什么都没有!如果你在箭头函数引用了thisarguments或者参数之外的变量,那它们一定不是箭头函数本身包含的,而是从父级作用域继承的。

什么情况下该使用箭头函数

到这里,我们可以发现箭头函数并不是万金油,稍不留神就会踩坑。

至于什么情况该使用箭头函数,《You Don’t Know JS》给出了一个决策图: arrow

以上决策图看起来有点复杂,我认为有三点比较重要:

  1. 箭头函数适合于无复杂逻辑或者无副作用的纯函数场景下,例如用在mapreducefilter的回调函数定义中;
  2. 不要在最外层定义箭头函数,因为在函数内部操作this会很容易污染全局作用域。最起码在箭头函数外部包一层普通函数,将this控制在可见的范围内;
  3. 如开头所述,箭头函数最吸引人的地方是简洁。在有多层函数嵌套的情况下,箭头函数的简洁性并没有很大的提升,反而影响了函数的作用范围的识别度,这种情况不建议使用箭头函数。
原文地址: 点此
社区评论 ( Beta版 )
  • #0 蒲风尼 1483579942514

    扯淡

    这是不对的

    helloworld
    
    • 那又怎样
OnceDoc 您自己的企业内容管理系统——文档、流程、知识库、报表、网盘All In One

访问404页面,寻找丢失儿童
 热门文章 - 分享最多
  1. NodeJS中的客户端缓存、浏览器缓存、304缓存和OnceIO的缓存控制
  2. 在Debian上安装Nginx并搭建一个最简单的静态网站服务器(以OnceAI为例)
  3. NodeJS中的Middleware是什么?在OnceIO中创建和使用中间件
  4. OnceIO(NodeJS)中的服务器端缓存、模板预加载和静态资源文件的缓存和Gzip压缩机制
  5. OnceIO(Node.JS)中的模板引擎是什么及MVC设计模式的使用与实现
  6. NodeJS教程:基于OnceIO框架实现文件上传和验证
  7. OnceIO(Node.JS)的静态文件路由(app.static)
  8. OnceIO(Node.JS)的网页(模板)的引用与嵌套
  9. OnceIO(Node.JS)服务器端Cookie设置、添加、删除、显示及其实现原理
  10. OnceIO(Node.JS)的路由(Routing)、路由方法和路由变量
  11. AirJD-简单好用的免费建站工具

 相关阅读 - JS学习
  1. NodeJS教程:基于OnceIO框架实现文件上传和验证
  2. 在Debian(Raspberry Pi)树莓派上安装NodeJS
  3. OnceIO(Node.JS)服务器端Cookie设置、添加、删除、显示及其实现原理
  4. OnceIO(Node.JS)的网页(模板)的引用与嵌套
  5. OnceIO(NodeJS)中的服务器端缓存、模板预加载和静态资源文件的缓存和Gzip压缩机制
  6. NodeJS中的客户端缓存、浏览器缓存、304缓存和OnceIO的缓存控制
  7. OnceIO(Node.JS)的路由(Routing)、路由方法和路由变量
  8. Node.JS的表单提交及OnceIO中接受GET/POST数据的三种方法
  9. OnceIO(Node.JS)中安装、使用和更换doT、EJS、pug等模板引擎
  10. OnceIO(Node.JS)中的模板引擎是什么及MVC设计模式的使用与实现

 关键字 - JavaScript
  1. 7个最新的实用性 JavaScript MV*框架
  2. 抛弃jQuery,深入原生的JavaScript
  3. WebPack:更优秀的模块依赖管理工具,及require.js的缺陷
  4. 5个现在就该使用的数组Array方法: indexOf/filter/forEach/map/reduce详解
  5. 用HTML5原生实现拖放或排序
  6. 少年,不要滥用箭头函数啊:JS中lambda表达式的优缺点和使用场景
  7. 用原生HTML5控件实现输入框自动提示(下拉列表补全)功能
  8. OnceIO模块开发:模块注册、模块路由、静态文件重定向以及如何开发与设计一个功能扩展模块
  9. JavaScript中NaN的秘密
  10. 从一行CSS调试代码中学到的JavaScript知识

 欢迎订阅 - 技术周刊

我们热爱编程, 我们热爱技术; 我们是高端, 大气, 上档次, 有品味, 时刻需要和国际接轨的码农; 欢迎您订阅我们的技术周刊; 您只需要在右上角输入您的邮箱即可; 我们注重您的隐私,您可以随时退订.
加入我们吧! 让我们一起找寻码农的快乐,探索技术, 发现IT人生的乐趣;


 关注我们

我们的微信公众号: ourjs-com
打开微信扫一扫即可关注我们:
IT文摘-程序员(码农)技术周刊

ourjs官方微信号