如何了解ES最新提案

5,841 阅读6分钟

还没学完ES6?现在的规范已经出到ES10(ES2019)了!读完本文,从今以后在前端娱乐圈谈笑风声。

文章目的

本文旨在让你了解ES最新进展,包括已经纳入标准的特性和目前进展中的提案(proposal),并掌握自主学习的能力。为了方便学习和使用,本文还给出了以下途径(见附录):

  1. ES最新标准和提案
  2. 浏览器内核对新特性的实现报告
  3. V8引擎对新特性的实现程度
  4. Node对新特性的实现程度

术语与关系

  • ECMAScript
    ECMAScript是JavasSript的语言标准(Language Specification),它是一份文件。其描述JS语言应该具备的能力、API(包括暴露的外部API和内部API)、基本实现步骤。目前最普遍的标准是ES6(2015),最新的标准是ES10。对于未来的ES标准,则统称为ESNext,其含义为当前时间后的下一代ES标准。

  • ECMAScript与Javascript关系
    ECMAScript之于JS,如同C99之于C。JS是ECMA的具体实现。

  • V8与Node关系
    V8是按照ECMAScript规范编写的一个语言引擎,可以运行JS代码。Node的内置引擎为V8,外层为Libuv这一异步IO库。

  • Proposal
    是JS社区希望未来添加的特性描述提案。经过几个环节的评审之后正式纳入ECMA标准,并在未来被各个厂商的JS引擎实现。

  • TC39
    出台ECMAScript的委员会,很多浏览器厂商在内。

关于提案

提案分为六种状态/阶段,这里有详细描述The TC39 Process

  1. Stage 0/Strawperson 初步的想法
  2. Stage 1/Proposal 已经包含了API描述、使用示例、主要挑战等。委员会(tc39)对此有兴趣,并分配Champion。
  3. Stage 2/Draft 使用规范化的方式描述,委员会希望能被实现。
  4. Stage 3/Candidate 进一步完善。
  5. Stage 4/Finished 已经完成,将在下一版的标准中正式发布。
  6. Inactive 这不是一个标准的流程,但在tc39的proposal中有将其划为一类,指的是被拒绝或撤回的提案。

目前的提案可以在GitHub - tc39/proposals: Tracking ECMAScript Proposals获取。其中进入Stage2的提案已经有较大可能最终实现。注意finished中的表格有Expected Publication Year一栏,其中部分已经释放出来了,比如Rest/Spread Properties、Promise.prototype.finally。

当然具体能不能用还要看V8等引擎的实现(部分不稳定的特性可以通过harmony flag开启),一般情况下当提案进入靠后阶段,提出者或者社区会提出polyfill方案,可以在提案的github仓库查看polyfill或者使用babel插件提前尝鲜GitHub - babel/proposals: ✍️ Tracking the status of Babel’s implementation of TC39 proposals (may be out of date)

当进入Stage4后,提案编写的测试用例将合入test262,Js引擎则可以实现功能并通过测试用例来证明具备该能力,一般会将新支持的特性包含在释出文档中。以QuickJs这一小型引擎对Promise.prototype.finally的支持为例:

test262对于Promise.prototype.finally的用例:

QuickJs文档中关于test262的说明:

Promise.prototype.finally 实现入口:

static const JSCFunctionListEntry js_promise_proto_funcs[] = {
    JS_CFUNC_DEF("then", 2, js_promise_then ),
    JS_CFUNC_DEF("catch", 1, js_promise_catch ),
    JS_CFUNC_DEF("finally", 1, js_promise_finally ),
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Promise", JS_PROP_CONFIGURABLE ),
};

QuickJs得到的测试报告:

各个JS引擎对test262的覆盖率在Test262 Report中有完整的报告。

主要发展方向

从ES6以来的诸多特性ES6、ES7、ES8、ES9、ES10新特性一览 - 掘金可以看出,提案比较密集的区域有:

  • 面向对象: 包括创建对象、继承对象、私有变量、装饰器、静态方法等
  • 异步:包括Promise、Async、for-await-of等
  • 内存操作:包括ArrayBuffer、SharedArrayBuffer、Atomics等
  • 元编程:包括Reflect、Proxy、Object.values等
  • 模块机制:包括import\export、import()、top-level-await等

实用特性列举

本文的目的并非罗列知识点,这里并不特意介绍最新的特性,仅从ES6到最新提案中摘取几个笔者认为较为实用的,对我们目前常见写法可能造成影响,改写后能够获得明显收益的。

Promise/Async——MVP颁给这对组合

相当成熟,近年来影响最大的特性。关于其理解摘抄笔者在V2ex的问题描述,其中多有谬误之处:

Promise 本质上还是 eventloop 机制,JS 在原有的 task 队列外新增了 promise 的 job 队列,每次 eventloop 时先看 job 队列,清空后再看 task 队列。

Generator 是 JS 中的协程,在一个函数内标注 yield,遇到该段代码时保存函数执行上下文,跳出当前函数执行接下来的函数,手动 next 时再恢复到上一个保存的函数执行现场。 这样在做 io 操作时发出了系统调用后就保存住现场继续把 cpu 释放给其他代码块,等到调用完成拷贝到应用空间时再回来执行。

async\await 是利用 Promise 对 Generator 进行了封装,实现了自动 next,实质上就是 io 操作完成后的 callback 执行了 next。

对象及数组解构——显著减少代码量

相信大多数人都会用,这里仅提两点:

  1. 新提案已经允许在解构中使用reset参数
  2. 可以声明后再解构赋值:let name = ''; ({name} = {name:"otisqzhang"});

Array.prototype.includes——去掉丑陋的indexOf(xx)!==-1

Includes可以判断是否存在某个元素,返回布尔值而非索引位置。以往为了判断有无而写的indexOf(xx)!==-1可以写的优雅点了。

Optional Chaining——Uncaught TypeError良药

你一定写过大量的 aa.bb && aa.bb.cc 等利用短路来兼容潜在的Uncaught TypeError: Cannot read property 'xx' of undefined错误。Optional Chaining提案已经进入finished阶段,计划2020年释出。到时候就可以使用aa?.bb?.cc的写法了,结合Nullish coalescing Operator 更香了。

还有for-await-of、Promise.finally 等相当多实用的特性不一而足,这里仅抛砖引玉。

更多途径

了解提案

最新提案: GitHub - tc39/proposals: Tracking ECMAScript Proposals

了解标准

了解实现

最全面的特性table(包括babel、浏览器、node等):ECMAScript compat table

  • 各个node版本的支持程度(实测有误,比如promise.prototype.finally,在V8 5.8+即支持通过harmony flag使用):Node.js support