还没学完ES6?现在的规范已经出到ES10(ES2019)了!读完本文,从今以后在前端娱乐圈谈笑风声。
文章目的
本文旨在让你了解ES最新进展,包括已经纳入标准的特性和目前进展中的提案(proposal),并掌握自主学习的能力。为了方便学习和使用,本文还给出了以下途径(见附录):
- ES最新标准和提案
- 浏览器内核对新特性的实现报告
- V8引擎对新特性的实现程度
- 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:
- Stage 0/Strawperson 初步的想法
- Stage 1/Proposal 已经包含了API描述、使用示例、主要挑战等。委员会(tc39)对此有兴趣,并分配Champion。
- Stage 2/Draft 使用规范化的方式描述,委员会希望能被实现。
- Stage 3/Candidate 进一步完善。
- Stage 4/Finished 已经完成,将在下一版的标准中正式发布。
- 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。
对象及数组解构——显著减少代码量
相信大多数人都会用,这里仅提两点:
- 新提案已经允许在解构中使用reset参数
- 可以声明后再解构赋值:
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
了解标准
- ES10:ECMAScript® 2019 Language Specification
- ES9:ECMAScript® 2018 Language Specification
- ES8:ECMAScript® 2017 Language Specification
- ES7:ECMAScript® 2016 Language Specification
- ES6:ECMAScript® 2015 Language Specification
了解实现
最全面的特性table(包括babel、浏览器、node等):ECMAScript compat table
- 各个node版本的支持程度(实测有误,比如promise.prototype.finally,在V8 5.8+即支持通过harmony flag使用):Node.js support
- V8引擎的支持程度:Features · V8
- Node版本释放进度: nodejs.org/en/about/re…
- 浏览器引擎的支持程度:Test262 Report
- 性能测试:jsperf.com/