先上一张图,感受一下 JavaScript
语言的博大精深吧!里面可能有些用法你还没用过,别着急,在不久的将来他们都会被支持上,因为有一帮人正在努力的推动这些提案进行标准化。今天我们就来梳理下,我们经常会听到的 ECMA262、ECMAScript、TC39
究竟是啥关系
ECMA-262、ECMAScript、JavaScript
Ecma International
(以前叫 ECMA - European Computer Manufacturers Association
)是个行业标准组织,它所通过的标准都是 ECMA-<nnn>
这样的编号,然后可以有另外的标准名字。
最初 JavaScript
语言有 2 份标准:
ECMA-262
:主标准,由 ECMA 国际组织(Ecma International
)负责管理(为了让最初的JavaScript
与最初的JScript
能遵循同一套标准发展而诞生的ECMAScript
,正好排到了作为Ecma
的262
号标准,所以得到ECMA-262
编号。)ISO/IEC 16262
:第二标准,由国际标准化组织(ISO,International Organization for Standardization
)和国际电子技术委员会(IEC,International Electrotechnical Commission
)负责管理
出于商标版权的原因,规范标准中将这门语言称为 ECMAScript
,所以原则上 JavaScript
与 ECMAScript
指的是同一个东西,但有时也会加以区分:
JavaScript
:指语言及其实现ECMAScript
:指语言标准及语言版本,比如 ES6 表示语言(标准)的第 6 版
TC39
TC39
指的是技术委员会( Technical Committee
)第 39
号,一个推动 JavaScript
发展的委员会。它是 ECMA
的一部分, ECMA
是 “ ECMAScript
” 规范下的 JavaScript
语言标准化的机构。
TC39
由各个主流浏览器厂商的代表构成,当然国内一些大型的科技公司比如阿里和字节都已经加入了 TC39
。他们的主要工作就是制定 ECMAScript
标准,标准生成的流程,并实现。
除
TC39
外,ECMA
国际组织还有有众多其他的技术委员会,比如 TC43 Universal 3D (U3D)、TC45 Office Open XML Formats 等等。
ECMAScript 发展历史
经过漫长的发展, ECMAScript
已经经过了多个大版本的迭代:
ECMAScript 1
(1997 年 6 月):规范第一版ECMAScript 2
(1998 年 6 月):为了同步 ISO 标准,引入了一些小更新ECMAScript 3
(1999 年 12 月):增加了正则表达式、字符串处理、控制语句(do-while、switch)、异常处理(try-catch)等众多核心特性ECMAScript 4
(2008 年 7 月废除):本来是一次大规模升级(静态类型、模块、命名空间等),但跨度过大,出现了分歧,最终没能推广使用ECMAScript 5
(2009 年 12 月):变化不大,加了一些标准库特性和严格模式
ECMAScript- 5
.1(2011 年 6 月):又一次小更新,为了同步 ISO 标准
ECMAScript 6
(2015 年 6 月):一大波更新,实现了当年 ES4 的许多设想,并正式改为按年份命名规范版本ECMAScript 2016
(2016 年 6 月):第一个年度版本,与 ES6 相比,发布周期较短,新特性也相对少些ECMAScript 2017
(2017 年 6 月):第二个年度版本
以后的 ECMAScript 版本(ES2018、ES2019、ES2020 等)都在 6 月正式获准生效
可见, ES3
出来之后,他们花了十年时间,几乎没有任何改变,使其达到规范。之后, ES6
又花了四年才能实现。发版周期过长存在 2
个问题:
版本之间的时间跨度太长,提早定稿的特性要等待非常长的时间,一直等到规范正式发布(才能被实现和使用),而靠后的特性往往赶在最后发版期限之前才定稿,存在风险,语言特性的设计与实现和使用相隔太久,在实现和使用阶段才发现设计缺陷为时已晚。
为此, TC39
精简了提案的修订过程,新流程使用 HTML
的超集来格式化提案,使用 GitHub pull requests
的模式来增加社区参与度。
标准指定流程
从 ES2016
开始(新 TC39
流程施行以来), ES
版本的概念被大大弱化了,需要关心的是特性提案处于第几阶段,只要进入第 4 阶段就已经算是标准特性了
stage0 strawman
:任何讨论、想法、改变或者还没加到提案的特性都在这个阶段。只有TC39成员可以提交。stage1 proposal
(1)产出一个正式的提案。(2)发现潜在的问题,例如与其他特性的关系,实现难题。(3)提案包括详细的API描述,使用例子,以及关于相关的语义和算法。stage2 draft
(1)提供一个初始的草案规范,与最终标准中包含的特性不会有太大差别。草案之后,原则上只接受增量修改。(2)开始实验如何实现,实现形式包括polyfill, 实现引擎(提供草案执行本地支持),或者编译转换(例如babel)stage3 candidate
(1)候选阶段,获得具体实现和用户的反馈。此后,只有在实现和使用过程中出现了重大问题才会修改。(1)规范文档必须是完整的,评审人和ECMAScript的编辑要在规范上签字。(2)至少要在一个浏览器中实现,提供polyfill或者babel插件。stage4 finished
(1)已经准备就绪,该特性会出现在下个版本的ECMAScript规范之中。(2)需要通过有2个独立的实现并通过验收测试,以获取使用过程中的重要实践经验。
你可以来这里:
https://github.com/tc39/proposals
看到所有正在进行中的TC39
提案
使用
如果你想用到上面还没被规范化的提案,可以使用下面的 babel
插件:
- babel-presets-stage-0
- babel-presets-stage-1
- babel-presets-stage-2
- babel-presets-stage-3
- babel-presets-stage-4
向后兼容
我们发现 ES 规范每一版始终完全兼容先前的所有特性,比如 ES6 提出了let、const但并没有干掉var,这是因为如果推出了不兼容的新版本,会造成一些问题:
JavaScript
引擎、IDE、构建工具都会变得臃肿,因为要支持新旧两版规范- 开发者需要知道版本之间的差异
- 要么把现有的代码全都迁移到新版本,要么(不同项目)混用多个版本,重构会变得很麻烦
- 甚至要标注每段代码的所属版本,就像 ES5 手动开启严格模式一样,当时没有流行起来的一个原因是在文件或函数开头添加指令也很麻烦
为了避免这些问题, ES6
采用了一种策略叫 One JavaScript
:
- 新版本始终完全向后兼容(但偶尔可能会有轻微、不明显的清理)
- 旧特性不删除也不修复,而是引入更好的版本,比如let就是var的改进版
- 如果语言的某些方面有变化,只在新的语法结构内生效,即隐式选用,例如,yield只在generator中才是关键字、模块和类中的所有代码都默认开启严格模式
参考
- http://www.ayqy.net/blog/tc39-work-flow/
- https://zhuanlan.zhihu.com/p/27762556