深入理解JavaScript中的箭头函数


Posted in Javascript onJuly 28, 2015

从一开始箭头就是 JavaScript 的一部分,在第一个 JavaScript 中就建议将内联的脚本代码包裹在 HTML 的注释中,这可以防止那些不支持 JavaScript 的浏览器错误滴将你的代码显示为明文。你也许写过下面这样的代码:

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

古老的浏览器将看到两个不被支持的标签和一段注释,只有支持 JavaScript 的新浏览器才会将其解析为 JavaScript 代码。

为了支持这个古怪的特性,浏览器的 JavaScript 引擎把 <!-- 作为一个单行注释的开始,这不是开玩笑的,这一直都是这门语言的一部分,并且至今还能用,不仅仅在 <script> 标签内的首行,而是在 JavaScript 代码的任何部位都可用,它甚至还能在 Node 中使用。

凑巧的是,这种风格的注释在 ES6 中首次被标准化。但这并不是我们将谈论的箭头。

--> 也表示一个单行注释,与 HTML 不同的是,在 HTML 中,--> 之前的部分是注释内容,而在 JavaScript 中,在 --> 之后的行才是注释。

只有当 --> 出现在一行的开始时,才表示该箭头是一个注释,因为在其他情况下,--> 是一个操作符(goes to)。

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

上面代码是真实能运行的。循环运行直到 n 为 0,这并不是 ES6 的新特性,但结合我们熟悉的特性,这具有很强的误导性。你能搞明白上面代码的运行情况吗?你可以在 Stack Overflow 上找到相应的解答。

当然还有一个箭头,那就是小于等于操作符 <=,也许你还可以找到使用箭头的地方,但我们还是停下来,看一个我们从没见过的箭头:

  •     <!-- 单行注释
  •     --> goes to 操作符
  •     <= 小于等于操作符
  •     => ???

那么,=> 表示什么呢?这就是本文将讨论的话题。

首先,我们来谈谈函数。
无处不在的函数表达式

JavaScript 一个有趣的特点是,任何时候你需要一个函数,你可以很方便地创建它们。

例如,为一个按钮绑定点击事件:

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

jQuery 的 .click() 方法需要一个函数作为参数,我们可以很方便地就地创建一个函数:

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

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

现在对我们来说,编写这样的代码是最自然的事了。但是在 JavaScript 流行起来之前,这种风格的代码看起来还是有些奇怪,因为在其他语言中都没有这样的特性。在 1958 年,Lisp 就有了函数表达式,也叫 lambda 函数,而在存在多年的 C++、Python、C# 和 Java 中没有该特性。

现在,这四门语言都有了 lambda 表达式,而且新出现的语言都普遍内置了 lambda 表达式。如今 JavaScript 也支持该特性了,这必须感谢那些重度依赖 lambda 表达式的库的开发者,这推动了该特性被广泛采纳。

与其他几门语言相比,JavaScript 的语法略显冗长:

// A very simple function in six languages.
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
 
// A very simple function in six languages.
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());

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

当你需要只有一个参数的函数,箭头函数的语法可以简化为 Identifier => Expression,直接省略了 function 和 return 关键字,连括号和结尾的分号也同时省略了。

编写一个有多个(或没有参数,或 Rest 参数和参数默认值,或解构参数)参数的函数,你需要用括号将参数括起来:

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

// ES6
var total = values.reduce((a, b) => a + b, 0);
 
// 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();
});
 
// ES5
$("#confetti-btn").click(function (event) {
 playTrumpet();
 fireConfettiCannon();
});

下面是采用箭头函数的写法:

// ES6
$("#confetti-btn").click(event => {
 playTrumpet();
 fireConfettiCannon();
});
 
// ES6
$("#confetti-btn").click(event => {
 playTrumpet();
 fireConfettiCannon();
});

需要注意的是,使用语句块的箭头函数不会自动返回一个值,必须显式地使用 return 来返回一个值。

还有一个忠告,当使用箭头函数来返回一个对象时,始终使用括号将返回的对象括起来:

// create a new empty object for each puppy to play with
var chewToys = puppies.map(puppy => {});  // BUG!
var chewToys = puppies.map(puppy => ({})); // ok

 
// create a new empty object for each puppy to play with
var chewToys = puppies.map(puppy => {});  // BUG!
var chewToys = puppies.map(puppy => ({})); // ok

因为空对象 {} 与空语句块 {} 看上去一模一样,ES6 将始终把紧跟在 => 后面的 { 当作语句块的开始,而不是一个对象的开始,那么 puppy => {} 就被解析为一个没有函数体的箭头函数,而且返回值为 undefined。

Javascript 相关文章推荐
Javascript读取cookie函数代码
Oct 16 Javascript
JavaScript中的prototype.bind()方法介绍
Apr 04 Javascript
jquery让返回的内容显示在特定div里(代码少而精悍)
Jun 23 Javascript
JavaScript利用正则表达式去除日期中的“-”
Jul 01 Javascript
jQuery中:lt选择器用法实例
Dec 29 Javascript
Python脚本后台运行的几种方式
Mar 09 Javascript
详解如何在vue项目中使用lodop打印插件
Sep 27 Javascript
原生Vue 实现右键菜单组件功能
Dec 16 Javascript
一篇文章带你浅入webpack的DLL优化打包
Feb 20 Javascript
es6中let和const的使用方法详解
Feb 24 Javascript
JS实现多功能计算器
Oct 28 Javascript
element tree树形组件回显数据问题解决
Aug 14 Javascript
解析JavaScript的ES6版本中的解构赋值
Jul 28 #Javascript
深入学习JavaScript中的Rest参数和参数默认值
Jul 28 #Javascript
JQuery实现鼠标滚轮滑动到页面节点
Jul 28 #Javascript
CSS3实现动态背景登录框的代码
Jul 28 #Javascript
javascript制作幻灯片(360度全景图片)
Jul 28 #Javascript
详解JavaScript ES6中的模板字符串
Jul 28 #Javascript
javascript解决IE6下hover问题的方法
Jul 28 #Javascript
You might like
层叠菜单的动态生成
2006/10/09 PHP
可以在线执行PHP代码包装修正版
2008/03/15 PHP
CodeIgniter启用缓存和清除缓存的方法
2014/06/12 PHP
PHP采用XML-RPC构造Web Service实例教程
2014/07/16 PHP
仿dedecms下拉分页样式修改的thinkphp分页类实例
2014/10/30 PHP
PHP自定义函数实现数组比较功能示例
2017/10/19 PHP
ThinkPHP3.2框架自定义配置和加载用法示例
2018/06/14 PHP
PHP parse_ini_file函数的应用与扩展操作示例
2019/01/07 PHP
stripos函数知识点实例分享
2019/02/11 PHP
Laravel Eloquent分表方法并使用模型关联的实现
2019/11/25 PHP
别了 JavaScript中的isXX系列
2012/08/01 Javascript
node+express+ejs制作简单页面上手指南
2014/11/26 Javascript
jQuery 处理页面的事件详解
2015/01/20 Javascript
js运动动画的八个知识点
2015/03/12 Javascript
深入分析Javascript跨域问题
2015/04/17 Javascript
jQuery ajax方法传递中文时出现中文乱码的解决方法
2016/07/25 Javascript
Js 获取、判断浏览器版本信息的简单方法
2016/08/08 Javascript
你真的了解BOM中的history对象吗
2017/02/13 Javascript
JS禁止浏览器右键查看元素或按F12审查元素自动关闭页面示例代码
2017/09/07 Javascript
JavaScript实现小球沿正弦曲线运动
2020/09/07 Javascript
JavaScript函数的特性与应用实践深入详解
2018/12/30 Javascript
Vue通过for循环随机生成不同的颜色或随机数的实例
2019/11/09 Javascript
JavaScript设计模型Iterator实例解析
2020/01/22 Javascript
jQuery表单校验插件validator使用方法详解
2020/02/18 jQuery
wxpython 学习笔记 第一天
2009/03/16 Python
python实战之实现excel读取、统计、写入的示例讲解
2018/05/02 Python
Django objects的查询结果转化为json的三种方式的方法
2018/11/07 Python
巧用 CSS3的webkit-box-reflect 倒影实现各类动效
2021/03/05 HTML / CSS
SIDESTEP荷兰:在线购买鞋子
2019/11/18 全球购物
介绍一下JMS编程步骤
2015/09/22 面试题
个人自我评价和职业目标
2014/01/24 职场文书
创业者迈进成功第一步:如何写创业计划书?
2014/03/22 职场文书
学习“七一”讲话精神体会
2014/07/08 职场文书
土建施工员岗位职责
2014/07/16 职场文书
毕业生爱心捐书倡议书
2015/04/27 职场文书
中学生打架检讨书之500字
2019/08/06 职场文书