原作者:江凌

箭头一族缺少的家庭成员

在JavaScript出现以来,箭头(Arrow)就一直是其语法的一部分。一般来说,JavaScript教程的第一篇就会讲如何在HTML中插入箭头括号来作为注释,这会阻止不支持JS的浏览器错误的将你的JS代码作为文字展现出来,比如这个:

<script language="javascript"><!--document.bgColor = "brown";  // red// --></script>

老旧的浏览器只会看到两个不支持的tag以及一个注释,而现代浏览器则会看到JS代码。

注:其实这是一种hack写法,在如今现代浏览器都支持JS的情况下已经慢慢不会再出现这种代码了

为了支持这个这个古怪的hack写法,浏览器的JavaScript引擎把 <!--当成了一行注释,这不是开玩笑,这成为了这个语言写法的一部分,并且直到现在都能正常使用。不只是在HTML的<script>中,在JS文件中也是一样,甚至在Node中它也是行得通的。

很巧合的是,我们在ES6中也首次有了注释的标准格式但是这不是我们现在想要说的箭头了,在此不赘述。

在-->之后的也会被当成一个注释,这点很古怪。你可以尝试在node里输入-->console.log(1) 结果发现被作为一个注释而没有被执行。
但是更古怪的是,只有在箭头出现在行首的时候才会被当成注释,这是因为-->在JS中是一个操作符,是一个趋向操作符!

function countdown(n) {while (n --> 0)  // "n goes to zero"alert(n);blastoff();
}

这个代码可以执行。它会从n一直循环到0,这不是ES6的特性,只是有一点小误导的简单特性,你能理解发生了什么吗?谜题的答案在这里可以找到。
那么,本该四人组的箭头还缺了谁呢?

<!-- 单行注释-->  趋向操作符<=   小于等于=>   ?=> 是ES6中新的用法,也就是本节要讲述的内容

更加简短的函数声明

JavaScript的一个很有趣的特性就是在你需要一个函数的时候,你可以把它写到文件中的任何一个地方。

举个例子,想象当你想要告诉浏览器你点击了一个特定的按钮的时候,你只需要打出:

$("#confetti-btn").click(

jQuery的click方法只有一个参数:一个函数,没有问题,你甚至可以直接这样写:

$("#confetti-btn").click(function (event) {playTrumpet();fireConfettiCannon();
});

在JS开始盛行前,这样的代码是令人奇怪的,因为很多语言当时都没有类似的写法。除了1958年List语言的lambda(匿名)函数有函数表达式功能,C++、Python、C#等语言长时间里都是没有的。到了现在,lambda已经随处可见了,这多亏了JS的功劳。

//六种语言的函数
function (a) { return a > 0; } // JS
[](int a) { return a > 0; }  // C++
(lambda (a) (> a 0))  ;; Lisp
lambda a: a > 0  # Python
a => a > 0  // C#
a -> a > 0  // Java

新的箭头语法

ES6为我们介绍了一个新的可以用来写函数的语法

// ES5
var selected = allJobs.filter(function (job) {return job.isSelected();
});// ES6
var selected = allJobs.filter(job => job.isSelected());

当你只是需要一个简单的单变量函数,箭头函数写起来就非常简单 Identifier => Expression 你可以省去了写function和return了,当然,还有中括号,小括号和分号。

(个人来说,我真的很喜欢这个语法,因为我现在不需要再每次都书写function了,我经常错写成functoin,而且每次都要回来检查和改正它)

如果你想要写一个多参数的函数(或者没有参数亦或是Rest参数,甚至是一个解构的变量),都是非常简单的,你可以直接把他们用括号包起来。

// ES5
var total = values.reduce(function (a, b) {return a + b;
}, 0);// ES6
var total = values.reduce((a, b) => a + b, 0);

我认为这是最简洁的书写格式。

箭头函数的功用与Underscore.js和immutable等库的功能类似,immutable的示例文档中全部都是使用ES6来编写的,因此使用了大量的箭头函数。

除了函数样式编写,箭头函数还可以包含区块语句而不仅仅是单一表达式。例如:

// ES5
$("#confetti-btn").click(function (event) {playTrumpet();fireConfettiCannon();
});
Here’s how it will look in ES6:// ES6
$("#confetti-btn").click(event => {playTrumpet();fireConfettiCannon();
});

只有一点点的改善,还不如使用Promise的提升更多。

但是有需要注意的几点:

1.当箭头函数包含的是区块的时候,它就不会自动return我们的结果

2.而且当我们想要直接使用箭头函数创造空对象,一定要将其包裹在括号里

var chewToys = puppies.map(puppy => {});   // BUG!
var chewToys = puppies.map(puppy => ({})); // ok

因为空对象和空区块长的一模一样,ES6在编译到{的时候会直接认为它是一个区块,而不是一个Object的开始,所以上面出bug的写法什么都不会做,因为其函数内部只是返回了一堆undefined

虽然我们会有很多疑惑,比如 {key:value} 这种也会看起来像是一个有标签陈述式的区块,而不是一个对象,不过幸运的是{是唯一的模糊字,所以我们只需要记住我们的对象要用括号包裹住就好。

只能继承parent的this值

普通函数与箭头函数有个微小的不同点。箭头函数没有自己的this值,其this值是通过继承其它传入对象而获得的。

JS是如何处理this的呢?this的值又是从何而来的呢?这可不是个简单的问题。如果你觉得这个已经很简单了,那么你真的是一名大牛了。

其中不论函数有没有真的需要处理this,函数都是会接收到的。你写过如下代码吗?

{//ES5...addAll: function addAll(pieces) {var self = this;_.each(pieces, function (piece) {self.add(piece);});},...
}

其实你想写的内联函数仅仅是this.add(piece)。然而内联函数不会继承外部函数的this值。在内联函数中,this的值是window或undefined。临时变量self用于向内联函数传入外部this值。

在ES6中,如果遵循如下原则则可避免类似的做法:

  • 使用非箭头函数处理由object.method()语法调用的方法。因为它们会接收到来自调用者的有意义的this值.
  • 在其它场合都使用箭头函数.
// ES6
{...addAll: function addAll(pieces) {_.each(pieces, piece => this.add(piece));},...
}

在ES6的版本中,你会注意到addAll函数已经从其调用者获得了this的值,而且它的内联函数是一个箭头函数,所以内敛函数的this继承了addAll的this。

在Object中其实ES6可以更为精简的写方法了,这是因为ES6中的增强字面量(enhanced object literals).

{ //ES6 with method syntax...addAll(pieces) {_.each(pieces, piece => this.add(piece));},...
}

箭头函数规范

箭头函数(Arrow Function)并非全能,在一些特别的场景并不适用,比如其没有函数名字,无法使用递归

  • 所有箭头函数的参数均使用()包裹,即便只有一个参数
// Good Style
let foo = (x) => x+1;
// Bad Style
let foo = x => x+1;
  • 定义函数尽可能使用箭头函数
// Good Style
let foo = () => {};// Bad Style
function foo() {}// Bad Style
let foo = function () {}

当然如上文的那些特殊情况不适用箭头函数的则不要使用

  • 在对象或者Class中定义函数,使用箭头函数
    这样能够最大程度的减少我们写一些多余的代码并且增加了代码的可读性。

拓展阅读

  • MDN 箭头函数规范
  • 本文由 ES6 In Depth: Arrow functions 翻译润色重新组织内容后合成

[译]深入ES6之箭头函数相关推荐

  1. button执行onclick函数_千万别再一直无脑使用ES6的箭头函数了,它虽然很有用但并不是万能的...

    相信很多小伙伴自从知道了ES6的箭头函数以后,都疯狂得使用,渐渐的淡忘了普通函数的使用.不过确实,箭头函数看起来比较简洁,用起来也舒服,不过它的出现是为了解决某一部分问题的,并不是用来替代普通函数的, ...

  2. ES6语法---箭头函数/关于this指向

    this指向问题: ES5:var obj = {x:1,func:function(){console.log(this.x);},test:function(){//定时器为异步setTimeou ...

  3. ES6中箭头函数解释

    箭头函数 任何可以书写匿名函数的位置,都可以书写箭头函数 箭头函数将会绑定this为函数书写位置的this值 模块化(nodejs带来的模块化) 没有模块化的世界:全局变量污染,难以管理 常见的模块化 ...

  4. es6语法-箭头函数

    箭头函数 创建 箭头函数.html 箭头函数提供了一种更加简洁的函数书写方式.基本语法是: 参数 => 函数体 // 传统 var f1 = function(a){return a } con ...

  5. 九、ES6的箭头函数

    一.箭头函数的基本使用 <!DOCTYPE html> <html lang="en"> <head><meta charset=&quo ...

  6. 深入ES6:箭头函数

    箭头从一开始就一直是JavaScript的一部分.第一个JavaScript教程建议在HTML注释中包装内联脚本.这会阻止不支持JS的浏览器错误地将JS代码显示为文本.你会写这样的东西: <sc ...

  7. es6语法 箭头函数

    一.语法形式: (参数1, 参数2, -, 参数N) => { 函数声明 }(参数1, 参数2, -, 参数N) => 表达式(单一) // 相当于:(参数1, 参数2, -, 参数N) ...

  8. JS ES6中的箭头函数(Arrow Functions)使用

    转载这篇ES6的箭头函数方便自己查阅. ES6可以使用"箭头"(=>)定义函数,注意是函数,不要使用这种方式定义类(构造器). 一.语法 基础语法 (参数1, 参数2, -, ...

  9. ES6 箭头函数理解

    你看懂"箭头函数"了么? 时间 2016-10-24 20:30:00   梁桂钊的博客 原文   http://blog.720ui.com/2016/es6_arrow_fun ...

最新文章

  1. 最大匹配、最小顶点覆盖、最大独立集、最小路径覆盖(转)
  2. ASP.net 自定义服务器控件之 GridViewControl
  3. 【Oracle】Oracle常用EVENT之三
  4. python算法与数据结构-插入排序算法(34)
  5. 计算机网络的组成和结构ppt,常见的计算机网络拓扑结构PPT课件.pptx
  6. set和multiset集合容器
  7. 【机器视觉学习笔记】大津法/Otsu最大类间方差法 最佳阈值处理(C++)
  8. java工程如何跑起来的_你编写的Java代码是咋跑起来的?
  9. Python风格总结:元组tuple
  10. Spring核心——资源数据管理
  11. GDI+中发生一般性错误的解决办法(转)
  12. C语言程序流程图switch,C语言流程控制之switch语句详解
  13. 小白建设一个网站需要什么资料?完整网站建设流程今天告诉你!
  14. Autumn中文文档0:为什么使用Autumn
  15. PHP中explode和implode的区别
  16. vscode关闭讨厌的单词拼写检查
  17. 关于域名备案后的注意事项,血淋淋的教训
  18. USACO section2.4 Cow Tours题解代码
  19. 全面解说OCA全贴合优势
  20. Apache POI(Word)教程_编程入门自学教程_菜鸟教程-免费教程分享

热门文章

  1. STM32驱动W5100实现udp通信
  2. 若两素数之差为2 ,则称两素数为双胞胎数,打印出[31,600]之间所有的双胞胎数,并求有多少对双胞胎数。
  3. linu学习第二天:文件系统相关操作
  4. 自控力极差的人如何自救?
  5. H5打造属于自己的视频播放器(JS篇1)
  6. DZ先生怪谈国标28181之利用crontab为linux服务器做时间同步
  7. 如何设计一个高并发的秒杀架构?
  8. 个人支付宝/微信/云闪付收款技术总览
  9. Android-NFC模块学习(1)
  10. 日志收集Agent,阴暗潮湿的地底世界