大家好,我是 世奇,笔名 ConardLi

先上一张图,感受一下 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 ,正好排到了作为 Ecma262 号标准,所以得到 ECMA-262 编号。)
  • ISO/IEC 16262:第二标准,由国际标准化组织(ISO,International Organization for Standardization)和国际电子技术委员会(IEC,International Electrotechnical Commission)负责管理

出于商标版权的原因,规范标准中将这门语言称为 ECMAScript ,所以原则上 JavaScriptECMAScript 指的是同一个东西,但有时也会加以区分:

  • 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中才是关键字、模块和类中的所有代码都默认开启严格模式

参考

如果你想加入高质量前端交流群,或者你有任何其他事情想和我交流也可以添加我的个人微信 ConardLi