« 回到博客列表

ECMAScript 2017 正式到来

不知不觉的到来

自打 ES2015 之后,ECMAScript 的发展就再没有什么特别大的动静,新特性加入得悄无声息,如果不是特意去关注,开发者们甚至都搞不清当前所用的新特性到底是哪一版引入的内容。不少特性在 ES2015 发布不久后就开始流行,甚至已经被广泛使用,但时至今日才正式被写入标准,新标准一发布,一看,卧槽这写特性我都用了好久了,怎么才写入标准。前端圈子这种实现先于标准的做法也是挺清奇的。

关于 ES6 系列

当然啦,《每天一点ES6》这个系列我还是会继续更新下去,ES6 涉及到的内容太多了,还有好些重要特性没有覆盖到呢。这里恰逢 ES2017 的定稿,因此中间插播一段。ES 标准的制订目前已经进入了一个比较稳定的发展节奏,浏览器厂商每 6 周一轮迭代,标准一年一发布,新想法从 Strawman(Stage 0),历经 Proposal(Stage 1)、Draft(Stage 2)、Candidate(Stage 3) 一路艰险,最终到达 Finished(Stage),才会正式被写入标准,中间任何一个环节不符合条件都不会出现在最终的标准当中(当然没被写入标准并不妨碍浏览器厂商们自己玩自己的,只要运行环境支持,开发者们依然可以照常使用)

ES 6.1

在正式开始介绍 ES2017 之前,我们先来看看它的前代 —— ES2016,或者称之为 ES 6.1,是继 ES2015 之后,于 2016 年年初正式发布的新一代 ES 标准,不过相比 ES2015 的“大跃进”,ES2016 收敛了很多,正式发布之前很多人都已经预料到这次的新增内容不会很多,可是也万万没想到 —— 整个标准居然一共就新增了两个新特性,与其说是一个全新的版本,不如说是对上一代的小幅补充,因此坊间也戏称之为 ES 6.1(当然这是个非正式的说法,ES2015 开始 ES 每年发布一套新标准,以年份为序命名)。

1) Array.prototype.includes

判断一个数组中是否包含指定项目,此前也可以通过简单遍历,或是更为高效的查询算法来进行查找判断,如今正式成为了语言的一部分,对于少量数据可以直接使用。

2) x ** y

幂运算,大部分情况下和Math.pow(x, y)是等效的,但由于实现算法的不同,在一些边缘情况下的结果会有差异。这一操作符借鉴了 Python、Ruby、Perl 等语言,使用上和常见的加减乘除一样。

进入正题:ES 2017

ES2017,或者叫 ES8,是 ECMAScript 目前的最新标准(标准的原文戳这里),相比前代做出了不少的改进,不过关注 ES 进展的朋友们看过后已经改会发现,这些特性早就已经用上了(感谢 Babel 和 各大浏览器开发商),所以没什么太大的惊喜,一共 6 个新特性,给大家注意列举下:

1) String.prototype.padStart 和 String.prototype.padEnd

还记得前不久发生的“Leftpad事件”吗?事件中的主角之一“leftpad”和这里提到的padStart其实是一个东西,原本 ES 不包含这一块,所以社区搞出了这么个模块,现在 ES 自己给实现了。

这两个方法分别用于从左、右方向,用指定内容补充字符串长度到指定的最小值,主流浏览器都已经原生支持了这一功能。举例说明下(以padStart为例,padEnd只是方向反一下,用法都一样):

let str = 'es8'
str.padStart(2)          // 'es8',原字符串已满足最小长度 2,不作为。
str.padStart(5)          // '  es8',原字符串长度不足最小长度 5,
                         // 从左边补足到 5,默认使用空格进行补足。
str.padStart(5, 'g')     // 'gges8',原字符串长度不足最小长度 5,从左边补足到 5,
                         // 指定使用字符'g'进行补足,重复多次直到满足最小长度。
str.padStart(5, 'great') // 'gres8',原字符串长度不足最小长度 5,从左边补足到 5,
                         // 指定使用字符'great'进行补足,但到'gr'为止已经达到最小长度5,停止补足。

2) Object.values() 和 Object.entries()

这两个方法跟 ES5 中的Object.keys()是配套的,Object.keys()返回对象属性名的数组,Object.values()返回对象属性值的数组,Object.entries()返回对象属性键值对的数组。按理说这些应该都是同期出现的函数,不知为何,后两者在 ES2015、ES2016 中都没赶上,直到 ES2017 才被正式写入标准。当然,根据实现早于标准的套路,这两个函数相信大家早就用上了,这里就不赘述了。

3) Object.getOwnPropertyDescriptors

在 ES5 中,就已经存在Object.getOwnPropertyDescriptor函数,用于返回一个对象的特定属性的描述(值、可修改性、可配置性、可枚举性、getter、setter)。从名字上不难看出,Object.getOwnPropertyDescriptors的作用就是传入一个对象,注意:返回的不是一个数组,是一个对象,对象的内容是这个对象所有自有属性的<属性名, 描述对象>键值对。

const obj = {x:1, y:2}
Object.getOwnPropertyDescriptors(obj)
// {
//   x: {value:1, writable:true, enumarable:true, configurable:true},
//   y: {value:2, writable:true, enumarable:true, configurable:true}
// }

4) 函数参数列表中的尾逗号

该特性允许我们在定义和调用函数时,传入多个参数的时候最后一个参数后面还能再跟一个逗号而不会引起报错。从复制粘贴的角度看来似乎确实有那么一小部分需求,ES 大发慈悲满足了大家。虽然这在大部分 Linter 看来是绝对不允许的,因此并不推荐大家这么用,只要知道这样的写法在不考虑 Lint 的情况下是合法的就行。

5) Async / Await

终于,可能是当前最好的原生异步方案的asyncawait终于被写入标准了,大家心里的石头终于放下了,原以为 ES2016 就可以包含进来,结果还是拖到了现在。相信大家该用的都已经用过了吧,那我给个案例就不多废话了。不了解的自己百度吧,大把大把的资料。

function asyncFunc() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("es8");
    }, 2000);
  });
}

async function sayHello() {
  const res = await asyncFunc();
  console.log(`Hello, ${res}`);
}

console.log(1);
sayHello();
console.log(2);
// 执行以上代码会立刻输出1、2,2秒后再输出'Hello, es8'

6) 共享内存和原子操作

ES2017 引入了 SharedArrayBuffer 的概念,允许多个线程并发读写同一个数据。上月发布的 v8 6.0 就已经包含了对 SharedArrayBuffer 的支持。

既然是并发,那就会遇到资源同步的问题,于是就引入了 Atomic 对象,它和 Math 对象一样不可实例化,起到命名空间的作用,暴露一些方法来提供原子操作,以确保下一操作必须等上一操作结束后才能开始。

小结

ES 标准的制订过程开始日趋稳定,开发者圈子也基本消化了 ES6 带来的巨变。在可预见的未来,我们会看到浏览器和 Node.js 继续高歌猛进支持大量新特性,其中备受欢迎的一些被写入标准,剩下的就作为民间土方法存在。照此看来,今后的 ES 标准与其说是标准,不如说是一部编年史,因为并非大家先统一好标准,然后都照着标准去做,而是大家先做起来,被广泛认可的功能像“被载入史册”一样被写进标准里,作为一种记录。这种做法未尝不可,可总有些怪怪的,但这就是社区,这就是工程师文化,本质上标准无非就是把先行者创造和踩坑的结果整合起来,写成一本指南留给后人,后人中具备探索精神的一部分,可以在此基础上继续深究,发现了更好的可以修改标准,至于不想去探索只想好好用的那部分人,照着标准走就行了,都标准了,肯定没问题的啦。