JavaScript ES6箭头函数使用指南


Posted in Javascript onDecember 30, 2018

胖箭头函数(Fat arrow functions),又称箭头函数,是一个来自ECMAScript 2015(又称ES6)的全新特性。有传闻说,箭头函数的语法=>,是受到了CoffeeScript 的影响,并且它与CoffeeScript中的=>语法一样,共享this上下文。

箭头函数的产生,主要由两个目的:更简洁的语法和与父作用域共享关键字this。接下来,让我们来看几个详细的例子。

新的函数语法

传统的JavaScript函数语法并没有提供任何的灵活性,每一次你需要定义一个函数时,你都必须输入function () {}。
CoffeeScript如今之所以那么火,有一个不可忽略的原因就是它有更简洁的函数语法。更简洁的函数语法在有大量回调函数的场景下好处特别明显,让我们从一个Promise链的例子看起:

function getVerifiedToken(selector) {
 return getUsers(selector)
  .then(function (users) { return users[0]; })
  .then(verifyUser)
  .then(function (user, verifiedToken) { return verifiedToken; })
  .catch(function (err) { log(err.stack); });
}

以下是使用新的箭头函数语法进行重构后的代码:

function getVerifiedToken(selector) {
 return getUsers(selector)
  .then(users => users[0])
  .then(verifyUser)
  .then((user, verifiedToken) => verifiedToken)
  .catch(err => log(err.stack));
}

以下是值得注意的几个要点:

function和{}都消失了,所有的回调函数都只出现在了一行里。
当只有一个参数时,()也消失了(rest参数是一个例外,如(...args) => ...)。
当{}消失后,return关键字也跟着消失了。单行的箭头函数会提供一个隐式的return(这样的函数在其他编程语言中常被成为lamda函数)。
这里再着重强调一下上述的最后一个要求。仅仅当箭头函数为单行的形式时,才会出现隐式的return。当箭头函数伴随着{}被声明,那么即使它是单行的,它也不会有隐式return:

const getVerifiedToken = selector => {
 return getUsers()
  .then(users => users[0])
  .then(verifyUser)
  .then((user, verifiedToken) => verifiedToken)
  .catch(err => log(err.stack));
}

如果我们的函数内只有一条声明(statement),我们可以不写{},这样看上去会和CoffeeScript中的函数非常相似:

const getVerifiedToken = selector =>
 getUsers()
  .then(users => users[0])
  .then(verifyUser)
  .then((user, verifiedToken) => verifiedToken)
  .catch(err => log(err.stack));

你没有看错,以上的例子是完全合法的ES6语法。当我们谈论只包含一条声明(statement)的箭头函数时,这并不意味着这条声明不能够分成多行写。

这里有一个坑,当忽略了{}后,我们该怎么返回空对象({})呢?

const emptyObject = () => {};
emptyObject(); // ?

不幸的是,空对象{}和空白函数代码块{}长得一模一样。以上的例子中,emptyObject的{}会被解释为一个空白函数代码块,所以emptyObject()会返回undefined。如果要在箭头函数中明确地返回一个空对象,则你不得不将{}包含在一对圆括号中(({})):

const emptyObject = () => ({});
emptyObject(); // {}

下面是一个更完整的例子:

function () { return 1; }
() => { return 1; }
() => 1
 
function (a) { return a * 2; }
(a) => { return a * 2; }
(a) => a * 2
a => a * 2
 
function (a, b) { return a * b; }
(a, b) => { return a * b; }
(a, b) => a * b
 
function () { return arguments[0]; }
(...args) => args[0]
 
() => {} // undefined
() => ({}) // {}

this

JavaScript中this的故事已经是非常古老了,每一个函数都有自己的上下文。以下例子的目的是使用jQuery来展示一个每秒都会更新的时钟:

$('.current-time').each(function () {
 setInterval(function () {
  $(this).text(Date.now());
 }, 1000);
});

当尝试在setInterval的回调中使用this来引用DOM元素时,很不幸,我们得到的只是一个属于回调函数自身上下文的this。一个通常的解决办法是定义一个that或者self变量:

$('.current-time').each(function () {
 var self = this;
 
 setInterval(function () {
  $(self).text(Date.now());
 }, 1000);
});

但当使用胖箭头函数时,这个问题就不复存在了。因为它不产生属于它自己上下文的this:

$('.current-time').each(function () {
 setInterval(() => $(this).text(Date.now()), 1000);
});

arguments变量

箭头函数与普通函数还有一个区别就是,它没有自己的arguments变量:

function log(msg) {
 const print = () => console.log(arguments[0]);
 print(`LOG: ${msg}`);
}
 
log('hello'); // hello

再次重申,箭头函数没有属于自己的this和arguments。但是,你仍可以通过rest参数,来得到所有传入的参数数组:

function log(msg) {
 const print = (...args) => console.log(args[0]);
 print(`LOG: ${msg}`);
}
 
log('hello'); // LOG: hello

关于yield

箭头函数不能作为generator函数使用。

最后

箭头函数是我最喜欢的ES6特性之一。使用=>来代替function是非常便捷的。但我也曾见过只使用=>来声明函数的代码,我并不认为这是好的做法,因为=>也提供了它区别于传统function,其所独有的特性。我个人推荐,仅在你需要使用它提供的新特性时,才使用它:

当只有一条声明(statement)语句时,隐式return。
需要使用到父作用域中的this。

本文详细说明了JavaScript ES6新特性之一的箭头函数的使用方法和一些注意事项,大家在使用时一定要注意,箭头函数用好了是非常快捷的,如果用不好的话也是非常令人头痛的

Javascript 相关文章推荐
Mootools 1.2教程 滑动效果(Slide)
Sep 15 Javascript
jQuery LigerUI 使用教程表格篇(1)
Jan 18 Javascript
JS遍历Json字符串中键值对先转成JSON对象再遍历
Aug 15 Javascript
JavaScript实现的字符串replaceAll函数代码分享
Apr 02 Javascript
APP中javascript+css3实现下拉刷新效果
Jan 27 Javascript
Extjs 点击复选框在表格中增加相关信息行
Jul 12 Javascript
Angular js 实现添加用户、修改密码、敏感字、下拉菜单的综合操作方法
Oct 24 Javascript
vue 使用Jade模板写html,stylus写css的方法
Feb 23 Javascript
vue-router实现编程式导航的代码实例
Jan 19 Javascript
ES6的异步操作之promise用法和async函数的具体使用
Dec 06 Javascript
vue中的过滤器及其时间格式化问题
Apr 09 Javascript
浅析JavaScript 函数柯里化
Sep 08 Javascript
JavaScript创建防篡改对象的方法分析
Dec 30 #Javascript
JavaScript事件对象深入详解
Dec 30 #Javascript
JavaScript继承的特性与实践应用深入详解
Dec 30 #Javascript
JavaScript函数的特性与应用实践深入详解
Dec 30 #Javascript
基于Three.js实现360度全景图片
Dec 30 #Javascript
three.js实现圆柱体
Dec 30 #Javascript
three.js实现炫酷的全景3D重力感应
Dec 30 #Javascript
You might like
古巴咖啡 Cubita琥爵咖啡 独特的加勒比海风味咖啡
2021/03/06 新手入门
PHP使用缓存即时输出内容(output buffering)的方法
2015/08/03 PHP
php+mysql开发的最简单在线题库(在线做题系统)完整案例
2019/03/30 PHP
微信JSSDK分享功能图文实例详解
2019/04/08 PHP
JS匀速运动演示示例代码
2013/11/26 Javascript
jquery对元素拖动排序示例
2014/01/16 Javascript
JQuery插件iScroll实现下拉刷新,滚动翻页特效
2014/06/22 Javascript
js获取时间并实现字符串和时间戳之间的转换
2015/01/05 Javascript
JavaScript动态添加列的方法
2015/03/25 Javascript
javascript实现简单的页面右下角提示信息框
2015/07/31 Javascript
巧用Javascript的逻辑运算符
2016/12/02 Javascript
Jquery Easyui菜单组件Menu使用详解(15)
2016/12/18 Javascript
Vue-router 类似Vuex实现组件化开发的示例
2017/09/15 Javascript
js根据json数据中的某一个属性来给数据分组的方法
2018/10/08 Javascript
jQuery - AJAX load() 实例用法详解
2019/08/27 jQuery
Vue.js实现大转盘抽奖总结及实现思路
2019/10/09 Javascript
js实现圆形菜单选择器
2020/12/03 Javascript
如何在Vue项目中添加接口监听遮罩
2021/01/25 Vue.js
[02:07]DOTA2新英雄展现中国元素,完美“圣典”亮相央视
2016/12/19 DOTA
python打开网页和暂停实例
2014/09/30 Python
浅谈解除装饰器作用(python3新增)
2018/10/15 Python
Python判断一个list中是否包含另一个list全部元素的方法分析
2018/12/24 Python
django的ORM操作 增加和查询
2019/07/26 Python
python文件处理fileinput使用方法详解
2020/01/02 Python
python 下载m3u8视频的示例代码
2020/11/11 Python
使用tkinter实现三子棋游戏
2021/02/25 Python
Data URI scheme详解和使用实例及图片base64编码实现方法
2014/05/08 HTML / CSS
Invicta手表官方商店:百年制表历史的瑞士腕表品牌
2019/09/26 全球购物
精彩的推荐信范文
2013/11/26 职场文书
放飞蜻蜓反思
2014/02/05 职场文书
文明风采获奖感言
2014/02/18 职场文书
上课迟到检讨书
2014/02/19 职场文书
学校领导班子群众路线整改措施
2014/09/16 职场文书
银行柜员与客户起冲突检讨书
2014/09/27 职场文书
工作违纪的检讨书范文
2019/07/09 职场文书
OpenCV中resize函数插值算法的实现过程(五种)
2021/06/05 Python