JS 开发者必须知道的十个 ES6 新特性

最近我参加了一个在旧金山举行的HTML5开发者大会,听到的演讲半数都关于ES6(或者官方说法叫ECMAScript2015),我喜欢简洁的成为ES6。

这篇文章会给你简单介绍一下ES6。如果你还不知道什么是ES6的话,它是JavaScript一个新的实现,如果你是一个忙碌的JavaScript开发者(但谁不是呢),那么继续读下去吧,看看当今最热门的语言——JavaScript的新一代实现中,最棒的十个特性。

这是为忙碌的开发者准备的ES6中最棒的十个特性(无特定顺序):

  1. 默认参数
  2. 模版表达式
  3. 多行字符串
  4. 拆包表达式
  5. 改进的对象表达式
  6. 箭头函数 =&>
  7. Promise
  8. 块级作用域的letconst
  9. 模块化

注意:这个列表十分主观并且带有偏见,其他未上榜的特性并不是因为没有作用,我这么做只是单纯的希望将这份列表中的项目保持在十个。

首先,一个简单的JavaScript时间线,不了解历史的人也无法创造历史。

  1. 1995年:JavaScript以LiveScript之名诞生
  2. 1997年:ECMAScript标准确立
  3. 1999年:ES3发布,IE5非常生气
  4. 2000年-2005年:XMLHttpRequest,熟知为AJAX,在如Outlook Web Access(2002)、Oddpost(2002)、Gmail(2004)、Google Maps(2005)中得到了广泛的应用
  5. 2009年:ES5发布(这是我们目前用的最多的版本),带来了forEach / Object.keys / Object.create(特地为Douglas Crockford所造,JSON标准创建者) ,还有JSON标准。

历史课上完了,我们回来讲编程。

1. ES6中的默认参数

还记得我们以前要这样子来定义默认参数:

这样做一直都没什么问题,直到参数的值为0,因为0在JavaScript中算是false值,它会直接变成后面硬编码的值而不是0本身。当然了,谁要用0来传值啊(讽刺脸)?所以我们也忽略了这个瑕疵,沿用了这个逻辑,否则的话只能…..没有否则!在ES6中,我们可以把这些默认值直接放在函数签名中。

对了,这个语法和Ruby很像!

2. ES6中的模版表达式

模版表达式在其他语言中一般是为了在模版字符串中输出变量,所以在ES5中,我们非得把字符串破开变成这样:

幸运的是在ES6中我们有了新语法,在反引号包裹的字符串中,使用${NAME}语法来表示模板字符:

3. ES6中的多行字符串

另一个好吃的语法糖就是多行字符串,以前我们的实现是像这样的:

但是在ES6中,只要充分利用反引号。

4. ES6中的拆包表达式

拆包可能是一个比较难理解的概念,因为这里面真的是有魔法发生。假如说你有一个简单的赋值表达式,把对象中的housemouse赋值为housemouse的变量。

另一个拆包的实例(Node.js):

但是在ES6中我们可以用以下语句替换:

甚至在数组中也能用,简直疯狂!

习惯拆包语法可能需要一些时间,但是这绝对是糖衣炮弹。

5. ES6中改进的对象表达式

你能用对象表达式所做的是超乎想象的!类定义的方法从ES5中一个美化版的JSON,进化到ES6中更像类的构造。

这是一个ES5中典型的对象表达式,定义了一些方法和属性。

如果你想做的好看一点,我们可以用Object.create方法来让 serviceBase 成为 accountServiceES5 的 prototype 从而实现继承。

我知道 accountServiceES5ObjectCreate 和 accountServiceES5 不完全相同的。因为一个对象 accountServiceES5 会有如下所示的 __proto__ 属性:

但对于这个示例,我们就把这两者考虑为相同的。所以在ES6的对象表达式中,我们把getAccounts: getAccounts简化为getAccounts,,并且我们还可以用__proto__直接设置prototype,这样听起来合理的多。(不过并不是用proto

还有,我们可以调用 super 和动态索引(valueOf_1_2_3)

这是对老旧的对象表达式一个很大的改进!

6. ES6中的箭头函数

这或许是我最想要的一个特性,我爱 CoffeeScript 就是因为他胖胖的箭头(=&>相对于-&>),现在ES6中也有了。这些箭头最神奇的地方在于他会让你写正确的代码。比如,this在上下文和函数中的值应当是相同的,它不会变化,通常变化的原因都是因为你创建了闭包。

使用箭头函数可以让我们不再用that = this或者self = this或者_this = this或者.bind(this)这样的代码,比如,这些代码在ES5中就特别丑。

这是在ES6中去掉_this = this之后:

可惜的是,ES6委员会觉得再加上瘦箭头(-&>)的话就对我们太好了,所以他们留下了一个老旧的function。(瘦箭头在CoffeeScript中的作用就像ES5/6中一样)

在ES6中我们无需_this

注意,在ES6中你可以合理的把箭头函数和旧式 function 函数混用。当箭头函数所在语句只有一行时,它就会变成一个表达式,它会直接返回这个语句的值。但是如果你有多行语句,你就要明确的使用return

这是ES5中利用messages数组创建一个数组的代码:

在ES6中会变成这样:

注意到我用了字符串模版吗,又一个从CoffeeScript中来的功能,我爱它们!

在只有一个参数的函数签名中,括号是可有可无的,但是如果多于一个参数时就要加上。

7. ES6中的Promise

Promise是一个有争议的话题。现在有很多Promise实现,语法也大致相同,比如q/ bluebird/ deferred.js/ vow/ avow/ jquery deferred等等。其他人说我们并不需要Promise,异步,回调和generator之类的就很好。庆幸的是,现在在ES6中终于有一个标准的Promise实现。

我们来看一个相当微不足道的延迟异步执行,用setTimeout实现

我们可以用ES6中的Promise重写:

或者用ES6的箭头函数:

到现在为止,我们只是单纯增加了代码的行数,还明显没有带来任何好处,你说的对。但是如果我们有更多复杂的逻辑内嵌在setTimeout()中的回调时好处就来了:

可以用ES6中的Promise重写:

还是无法相信Promise比普通回调要好?我也不信。我想一旦知道了回调这个方法它就会在你脑中萦绕,额外的复杂的Promise也没有必要存在了。

不论怎么说,ES6中的Promise是为会欣赏的人准备的,Promise有一个不错的失败-捕捉回调机制,看看这篇文章吧,里面有更多关于Promise的信息。ES6 Promise介绍

8. 块级作用域的letconst

你可能早就听过对ES6中的let那些奇怪的传说,我记得我第一次到伦敦时为那些TO LET牌子感到非常困惑。但是ES6中的let和出租无关,这不算是语法糖,它很复杂。let是一个更新的var,可以让你把变量作用域限制在当前块里。我们用{}来定义块,但是在ES5中这些花括号起不到任何作用。

运行结果将会是1000。天啊!这是多大的一个Bug。在ES6中,我们用let来限制变量作用域为函数内。

运行结果是0,因为在if块中也有let。如果什么都没有的话(amount=1),那么结果将会是1

说到const,事情就简单多了。他仅仅产生是一个不可变的变量,并且他的作用域也像let一样只有块级。为了演示,这里有定义了一堆常量,并且由于作用域的原因,这些定义都是有效的。

依我愚见,letconst让这门语言变得更加复杂,没有这些的时候我们只有一条路可以走,但是现在可以要考虑更多的情景。;-(

9. ES6中的类

如果你喜欢面向对象编程,那么你会特别喜欢这个特性。他让你编写和继承类时就跟在Facebook上发一个评论这么简单。

在ES5中,因为没有class关键字(但它是毫无作用的保留字),类的创建和使用是让人十分痛苦的事情。更惨的是,很多伪类的实现像pseude-classical, classical, functional让人越来越摸不着头脑,为JavaScript的信仰战争火上浇油。

我不会给你展示在ES5中怎么去编写一个类(是啦是啦从对象可以衍生出来其他的类和对象),因为有太多方法去完成。我们直接看ES6的示例,告诉你ES6的类会用prototype来实现而不是function。现在有一个baseModel类,其中我们可以定义构造函数和getName()方法。

注意到我给optionsdata用了默认参数,而且方法名再也不用加上function或者:了。还有一个很大的区别,你不能像构造函数里面一样向this.Name指派值。怎么说呢,和函数有相同缩进的代码里,你不能向name赋值。如果有这个需要的话,在构造函数里面完成。

使用NAME extends PARENT_NAME语法,AccountModelbaseModel继承而来。

调用父类构造函数时,只需带上参数轻松的调用super()方法。

想要高级一点的话,你可以像这样弄一个getter方法,这样accountsData就会变成一个属性。

现在你要怎么用这个魔咒,很简单,就跟让三岁小孩相信圣诞老人存在一样。

如果好奇输出结果的话:

10. ES6中的模块化

你可能知道,ES6之前JavaScript并没有对模块化有过原生的支持,人们想出来AMDRequireJSCommenJS等等,现在终于有importexport运算符来实现了。

ES5中你会用script标签和IIFE(立即执行函数),或者是其他的像AMD之类的库,但是ES6中你可以用export来暴露你的类。我是喜欢Node.js的人,所以我用和Node.js语法一样的CommonJS,然后用Browserfy来浏览器化。现在我们有一个port变量和getAccounts方法,在ES5中:

在ES5的main.js中,用require('模块')来导入:

但是在ES6中,我们用exportimport。比如这是ES6中的module.js文件:

在需要引入的main.js文件中,可以用import {名称} from '模块'语法:

或者就直接在main.js中引入所有的变量:

个人来说,我觉得这样的模块化有些搞不懂。确实,这样会更传神一些 。但是Node.js中的模块不会马上就改过来,浏览器和服务器的代码最好是用同样的标准,所以目前我还是会坚持CommonJS/Node.js的方式。

目前来说浏览器对ES6的支持还遥遥无期(本文写作时),所以你需要一些像jspm这样的工具来用ES6的模块。

想要了解更多ES6中的模块化和例子的话,来看这篇文章,不管怎么说,写现代化的JavaScript吧!

怎么样可以在今天就用上ES6(Babel)

ES6标准已经敲定,但还未被所有浏览器支持(Firefox的ES6功能一览),如果想马上就用上ES6,需要一个像Babel这样的编译器。你可以把他当独立工具用,也可以将他集成到构建系统里,Babel对GulpGruntWebpack都有对应的插件

安装Gulp插件示例:

gulpfile.js中,定义这么一个任务,将src目录下的app.js文件编译到build目录下:

Node.js和ES6

对于Node.js,你可以用构建工具或者直接用独立模块babel-core

然后在Node.js中调用这个函数:

ES6的一些总结

ES6中还有很多你可能都用不上(至少现在用不上)的可圈可点的特性,以下无特定顺序:

  1. Math / Number / String / Array / Object中新的方法
  2. 二进制和八进制数据类型
  3. 自动展开多余参数
  4. For of循环(又见面了CoffeeScript)
  5. Symbols
  6. 尾部调用优化
  7. generator
  8. 更新的数据结构(如MapSet

和有些人吃了一片薯片就一发不可收拾的人一样(再来一片嘛就一片),对于那些停不下来想要知道关于更多ES6相关信息的成绩优秀的同学,我准备了扩展阅读:

  1. ES6速查手册PDF
  2. Nicholas C. Zakas所著的理解ECMAScript6
  3. Dr. Axel Rauschmayer所著的探索ECMAScript6
2 9 收藏 1 评论

关于作者:吴鹏煜

童心、勇气、创意和传奇。(新浪微博:@Nappp) 个人主页 · 我的文章 · 13

相关文章

可能感兴趣的话题



直接登录
最新评论
跳到底部
返回顶部