24年前,我没想到JS会发展成为互联网上使用最广的编程语言...

论坛 期权论坛 期权     
图灵教育   2019-7-8 06:26   1785   0

图片来源:Unsplash
JavaScript 已经从 1995 年的一个为了赢得战略优势的市场营销策略,变成了如今(2017 年)世界上使用最广泛的应用运行平台中的核心编程语言。该语言不再只是在浏览器中运行,现在也用于创建桌面和移动应用,还用于硬件设备,甚至是 NASA 的太空服设计。
JavaScript 是如何做到这一步的,接下来它又会怎么做呢?
JavaScript标准简史1995 年,NetScape 公司想要构建一个动态的网页,但 HTML 无法实现这一点。为此,他们雇用 Brendan Eich 专门为浏览器开发一门功能类似于 Scheme 的语言。Brendan 加入之后,得知上级主管希望这门语言的语法像 Java,而且这一决定已经开始实施。
Brendan 花 10 天写出了 JavaScript 的第一个原型,主要实现了 Scheme 的一类函数和 Self 的原型等构造。这个初始版 JavaScript 的代号为 Mocha。它没有数组,没有对象字面量,任何错误都会给出警告。此外,它也没有异常处理,这也是如今仍有很多操作返回 NaN 或 undefined 的原因。Brendan 对 DOM0 级和 JavaScript 第一个版本的实现成为了这门语言标准化的基础。
1995 年 9 月,Netscape Navigator 2.0 beta 版发布,JavaScript 的修订版也内置其中,对外宣传时名叫 LiveScript。同年 12 月,Navigator 2.0 beta 3 发布,此时 LiveScript 又重新命名为 JavaScript(后成为 Sun 的注册商标,Sun 现在是 Oracle 旗下公司)。这次发布后不久,Netscape 公司推出了服务器端 JavaScript 的实现,用于在 Netscape Enterprise Server 上运行脚本,并将其命名为 LiveWire。① 1996 年,微软在 IE3 中推出 JScript,即通过逆向工程实现的 JavaScript。JScript 在服务器端也可以在互联网信息服务器(IIS,Internet information server)中运行。
① 1998 年的这个小册子(https://docs.oracle.com/cd/E19957-01/816-6411-10/contents.htm)详细介绍了服务器端 JavaScript 以及 LiveWire 的方方面面。
1996 年,ECMA 的一个技术委员会 TC39 将 JavaScript 以名称 ECMAScript(ES)标准化为 ECMA-262 规范。为什么叫 ECMAScript 呢?因为 Sun 不同意将 JavaScript 商标转让给 ECMA,虽然微软提议叫 JScript,但其他成员公司又不想用,结果就只能使用 ECMAScript 这个尴尬的名字。
当时,TC39 开会主要就是争论该采用 Netscape 的 JavaScript,还是微软的 JScript。尽管如此,该委员会还是取得了成果,他们坚定不移地支持向后兼容,推动引入了严格相等运算符(=== 和 !==),不会影响依赖松散相等比较算法的现有程序。
ECMA-262 的第一版于 1997 年 6 月发布。次年 6 月,国际标准化组织对这个规范进行了完善和认真审查,并以 ISO/IEC 16262 的形式发布,这就是它的第二版。
1999 年 12 月发布的第三版标准化了正则表达式、switch 语句、do/whille、try/catch、Object#hasOwnProperty,以及其他一些特性。其中大部分特性已经可以在 Netscape 的 JavaScript 运行环境 SpiderMonkey 中使用。
之后不久,TC39 发布了 ES4 规范的草案。ES4 的早期工作直接导致了 2000 年年中 JScript.NET 的产生②,并最终促进 2006 年 Flash 中 ActionScript 3 的诞生。③
② 可以在微软网站上找到最初的公告(2000 年 7 月)。
③ Brendan Eich 在播客 JavaScript Jabber 中介绍了很多关于 JavaScript 起源的故事。
此时,关于 JavaScript 应该朝哪个方向发展的不同意见导致了规范制定工作停滞不前。对于 Web 标准的发展而言,这时的情形很微妙:微软几乎垄断了 Web 行业,却对制定标准毫无兴趣。
2003 年,AOL 裁掉了 50 名 Netscape 员工④,Mozilla 基金会随之成立。同时,由于微软占据了超过 95% 的 Web 浏览器市场份额,TC39 被迫解散。
④ 2003 年 7 月的 The Mac Observer 有该新闻的相关报道。
直到两年后,Brendan 在 Mozilla 以 Firefox 日益增长的市场份额为杠杆使得微软回归,ECMA 才得以重新开始 TC39 的相关工作。2005 年年中,TC39 再次开始召开定期会议。对于 ES4,计划引入模块系统、类、迭代器、生成器、解构、类型注释、尾调用优化、代数类型以及其他各类功能。这次的新增内容过于庞大,导致 ES4 一次又一次地延期了。
2007 年,TC39 分裂为两派:一派主张推出 ES3.1,即只在 ES3 的基础上完善改进;另一派则主张推出 ES4,新特性繁多,且亟待规范化。直到 2008 年 8 月⑤,两派才就 ES3.1 达成一致,ES3.1 后来又发展为 ES5。ES4 的提议似乎废弃了,但实际上其中很多特性最终写进了 ES6(达成和解时美其名曰 Harmony,即“和谐”),当然,其中一些特性还在讨论,另外少数特性确实已经废弃、被拒或撤销。ES3.1 也为 ES4 的逐步实现奠定了基础。
⑤ 2008 年,Brendan Eich 给 es-discuss 发了一封邮件,其中介绍了当时的情况,此时距 ES3 发布都快 10 年了。
2009 年 12 月,ES3 发布 10 周年,ECMAScript 第五版发布。这一版汇集了当时浏览器中业已存在的扩展,或者说“事实标准”,增加了 get 和 set 存取器,增强了 Array 原型的函数特性,还引入了反射和内省机制,以及对 JSON 解析和严格模式的支持。
2011 年 6 月,经过再次审查和编辑,该规范形成了第三版的国际标准 ISO/IEC 16262:2011,并作为 ECMAScript 5.1 发布。
2015 年 6 月,TC39 又花 4 年完成了 ECMAScript 6。第六版是该语言面世以来改动最大的一个版本,实现了许多 ES4 中被推迟到 Harmony 中的提案。本书主要探讨的就是 ES6。
在 ES6 的制定过程中,另一个旨在推动 Web 发展的组织 WHATWG(网页超文本应用技术工作小组)于 2012 年推出了一个文档,以记录 ES5.1 和浏览器实现在兼容性和可操作性方面的差异。这个工作小组标准化了之前规范中没有提及的 String#substr,统一了在 HTML 标签中包装字符串的几种方法,明确写出了 Object.prototype 中的 __proto__ 和 __defineGeter__ 等原型属性,同时还做出了其他一些改进。⑥ 这些工作最终形成了一份独立的 Web ECMAScript 规范,最终于 2015 年被加入到附录 B 中。附录 B 是 ECMAScript 核心规范中的参考部分,这意味着浏览器可以不遵照其进行实现。此次更新之后,附录 B 也成为了 Web 浏览器的规范和要求。
⑥ 要想了解将 Web ECMAScript 规范合并到主干时所做的全部更改,请参见 WHATWG 博客。
第六版是 JavaScript 历史上一个意义重大的里程碑。除了众多新功能之外,ES6 也是 ECMAScript 成为持续迭代标准的一个转折点。
持续迭代的ECMAScriptES3 在 10 年内未有重大改变,之后 4 年才推出 ES6。这一漫长历程清楚地表明 TC39 流程需要改进。之前的修订流程是最终发布日期驱动的。只要有议题未能达成一致,下次修订就会变得遥遥无期。时间一长又会有新的特性提出,进而导致更多拖延。小的修订总会因大的新增而拖延,而大的新增迫于最终发布日期的压力,就会仓促通过修订,以免造成一拖再拖。
ES6 发布后,TC39 优化了提案修订的流程⑦,以满足现代预期:迭代具有经常性和一贯性,且规范的制定要更加民主化。基于这一点,TC39 不再采用古老的 Word 文档形式,而是使用 Ecmarkup(用于编写 ECMAScript 规范的 HTML 语言的超集)和 GitHub 来提交需求,大大增加了非成员的提案数量⑧,他们就像是外在的参与者一样。这种新形式是持续的,并且更加透明:最新的规范草案随时可以查看,而无须像之前那样,必须从网页下载 Word 文档或 PDF 版本。
⑦ 2013 年 9 月的 PPT,Post-ES6 Spec Process,介绍了优化后的提案修订流程。
⑧ TC39 采纳的提案参见 https://mjavascript.com/out/tc39-proposals。
Firefox、Chrome、Edge、Safari 以及 Node.js 对 ES6 规范的支持均已超过 95% ⑨。现在我们就可以在这些浏览器中使用已经支持的功能,而不用等到它们对 ES6 的支持度达到 100%。
⑨ ES6 的浏览器兼容性报告参见 https://kangax.github.io/compat-table/es6/。
新的流程引入了 4 个不同的成熟度阶段。⑩ 提案越成熟,最终添加到规范中的可能性越大。
⑩ TC39 的提案流程文档参见 https://tc39.github.io/process-document/。
只要还未作为正式提案提交,关于修改或新增内容的任何讨论、想法或者提议都会被视为有前途的“稻草人”提案(阶段 0),但只有 TC39 委员会的成员才可以创建“稻草人”提案。在编写本书时,有 10 多个活跃的“稻草人”提案。
“稻草人”提案参见 https://github.com/tc39/proposals/blob/master/stage-0-proposals.md。
阶段 1 表示提案被正式提出,希望能够解决各方关注的问题,厘清与其他提案的交集,并实现问题。这一阶段的提案需要明确描述一个具体的问题,并给出该问题的具体解决方案。阶段 1 的提案通常包括以下几方面的内容:高级 API 描述、演示性的用法示例、内部语义和算法的讨论。阶段 1 的提案可能会随着流程的推进而发生很大的改变。
阶段 2 的提案是规范的初步草案。从这一步开始,需要在运行环境中验证具体的实现。实现的方式可以是腻子脚本(polyfill)、能让运行环境支持提案的用户代码、原生支持提案内容的引擎实现,也可以是使用构建工具将源代码转换、编译成现有引擎可以执行的代码。
阶段 3 的提案是候选推荐提案。只有规范的编辑和指定的审查人员在最终的规范上签字确认,提案才能进入阶段 3。另外,还需要实现者表示出对该提案感兴趣。实际上,只有满足以下 3 个条件之一,提案才能进入阶段 3:某个浏览器已经实现该提案,有高度吻合的腻子脚本,有类似 Babel 的实时编译工具的支持。除了修复使用过程中新发现的问题,阶段 3 的提案不会再有其他改动。
要想进入阶段 4,提案必须有两个独立的实现方案通过验收测试。进入阶段 4 的提案最终会添加到 ECMAScript 的下一版中。
从现在开始,ECMAScript 预计每年都会发布新版本。为了与年度发版计划统一,规范的版本从现在开始与出版的年份相关联。因此,ES6 也就是 ES2015,之后将有 ES2016(而不是 ES7)、ES2017,等等。实际上,ES2015 这个称呼并没有被接受,大家还是习惯称其为 ES6。ES2016 也是在命名约定改变前就发布了的,因此有时人们也称其为 ES7。由于 ES6 这一名称已经为社区普遍接受,我们抛开不谈。最终的规范版本将是 ES6、ES2016、ES2017、ES2018,以此类推。
调整后的提案流程加上每年都发布一版的强制约定形成了更加一致的发布过程。这也意味着规范的修订版本号变得不再那么重要。现在的重点是提案的不同阶段,我们相信将来大家会越来越少提及 ECMAScript 标准的某个特定修订版。
浏览器支持和辅助工具如果能够有两个 JavaScript 引擎提供独立的实现,阶段 3 的候选推荐提案最有可能进入下一个版本的规范之中。实际上,只要阶段 3 的提案有实验性的引擎实现或者腻子脚本,再或者可以通过编译器得到支持,那么就已经能够安全地在实际开发中使用了。其实,阶段 2 和更早阶段的提案也有为 JavaScript 开发人员所使用的,这也加强了实现者和使用者之间的反馈循环。
Babel 等将代码作为输入并生成 Web 平台原生支持的输出(HTML、CSS 或 JavaScript)的编译器通常称为转译器(transpiler),它是编译器的一个子集。如果我们想要在代码中使用某个 JavaScript 引擎还没有普遍实现的提案,Babel 之类的编译器可以帮我们将相应的代码转换成现有 JavaScript 实现可以运行的代码。
代码转换是在构建时完成的,因此用户拿到的是自己的 JavaScript 运行环境所支持的代码。这一机制降低了对运行环境的要求,也让 JavaScript 开发者能够更早地使用新的语言功能和语法。对于规范的编写者和实现者来说,这也是非常有利的,因为这样他们就可以得到可行性、迫切性、可能存在的 bug,以及边界用例等方面的反馈。
转译器可以将 ES6 代码转换成浏览器普遍可以解释的 ES5 代码。这是如今在生产环境中运行 ES6 代码的最可靠方式:通过构建生成 ES5 代码,这样新旧浏览器都可以执行。
这种方式同样适用于 ES7 及后续版本。由于语言规范每年都会发布新版本,我们可以期待编译器支持 ES2017 输入、ES2018 输入,等等。同样,随着浏览器的支持度越来越好,编译器可以逐渐降低支持 ES6 输出、ES7 输出的复杂性。从这种意义上说,我们可以将 JavaScript 转译器看作移动的窗口,其输入是使用最新语法编写的代码,输出是不影响浏览器运行的最新代码。
接下来我们探讨如何在工作中使用 Babel。

1. Babel转译器简介
Babel 可以将 ES6 代码编译成 ES5 代码。生成的 ES5 代码很容易看懂,因此非常适合还不完全熟悉新特性的人来理解新特性。
Babel 的在线读取 - 求值 - 打印循环(REPL,read-evaluate-print loop)转换器是学习 ES6 的好帮手,无须安装 Node.js、babel CLI,也无须手工编译源码。
REPL 提供了一个源码输入框,用于自动实时编译,编译后的代码位于源码右侧。
我们可以在 REPL 中写几行代码,如下所示。
var double = value => value * 2
console.log(double(3))
//  value * 2
console.log(double(3))
//
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:10
帖子:2
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP