📜 ECMAScript 演进史

一句话定性

一门10 天赶制、为蹭 Java 热度而生的”玩具语言”,被时代推上了世界第一编程语言的宝座。它的整部演进史,就是一场**“如何在永不破坏旧网页的前提下,把仓促设计修补成现代语言”**的漫长工程——其中最惨痛的一课(ES4),教会了整个行业一个道理:在 Web 上,向后兼容不是美德,是物理定律。


一、它是什么 & 出现的时代

ECMAScript(ES)是标准,JavaScript 是实现。 这是理解整段历史的第一把钥匙。

1995 年,Netscape 的 浏览器需要一种”能在网页里跑、给设计师用”的脚本语言。Brendan Eich 用 10 天写出了它。它本该是 Scheme(一门 Lisp 方言)在浏览器里的化身——Eich 是被”做浏览器版 Scheme”这个承诺招进 Netscape 的——但管理层在最后关头改了主意:当时 Sun 的 Java 如日中天,市场部要求这门新语言”长得像 Java”以蹭热度。

于是诞生了一个披着 C/Java 语法外壳、内核却是 Scheme(函数是一等公民、闭包)+ Self(原型链) 的混血儿。连名字都是营销产物:它先叫 Mocha,再叫 LiveScript,最后在 Sun 的授权下改叫 JavaScript——一个和 Java 几乎毫无关系、却让无数初学者困惑至今的名字。

"10 天"是理解 JS 所有坑的根因

typeof null === 'object'、隐式类型转换的混乱([] + {})、== 的诡异规则、var 的变量提升、自动分号插入(ASI)——这些不是设计失误,而是没有时间设计的直接后果。更致命的是:一旦网页开始依赖这些行为,它们就永远无法被修复,只能靠后续标准”打补丁”绕过去。


二、为什么会出现标准化(解决厂商分叉的痛点)

JavaScript 一出生就遇到了 Web 的原罪:厂商分叉

微软看到 JS 的威力后,逆向做出了自己的 JScript(1996,装进 IE3)。两套语言行为不完全一致,开发者被迫为不同浏览器写不同代码。Netscape 意识到:如果不把语言交出去标准化,它迟早会像 HTML/CSS 一样被厂商各自魔改成一团乱麻。

于是 1996 年底,Netscape 把 JavaScript 提交给 ECMA International(欧洲计算机制造商协会)。为什么不是 W3C 或 ISO?因为 ECMA 流程快、政治包袱小。商标问题让标准没法叫”JavaScript”(Sun 持有商标),于是有了一个谁都不喜欢的名字:ECMAScript。Eich 本人吐槽它”听起来像一种皮肤病”。

版本年份历史地位
ES11997第一份标准,确立语言基准,目的是阻止厂商私有化
ES21998仅为对齐 ISO 标准的编辑性修订,无新特性
ES31999第一个广泛使用的版本:正则、异常处理、try/catchjQuery 时代的语言基础
ES4(流产)一场野心过大的灾难,见下文
ES52009务实的现代化:strict mode、JSON、Array 方法、Object.defineProperty
ES6-ES20152015分水岭:class/箭头函数/let/Promise/模块/解构
ES2016+每年改为年度小步发布(详见下文)

三、关键转折 & 为什么重要

① ES3(1999):第一个能用的版本

ES3 加上了正则表达式、try/catchdo-while、更好的字符串方法。它稳定了整整十年(1999→2009),成为 jQuery 等库赖以生存的最大公约数——因为它就是 IE6 支持的语言版本。详见 ES3

② ES4(1999–2008):那场流产的政治战争

ES4 是整段历史里最重要的失败。从 1999 年起,一群人想把 JS 改造成一门”真正的大型应用语言”:静态类型(类型注解)、class 与接口、命名空间、包系统——本质上是把 JS 变成另一门语言(很大程度上对标当时 Adobe/Macromedia 在 Flash 里用的 ActionScript 3,它正是基于 ES4 草案实现的)。

但这撕裂了 TC39 委员会:

       ES4 之争 (两大阵营)
┌────────────────────────┬────────────────────────┐
│  激进派 (大改)          │  保守派 (渐进)           │
│  Adobe/Macromedia       │  微软 / 雅虎             │
│  + Mozilla              │  (Doug Crockford 等)     │
├────────────────────────┼────────────────────────┤
│  静态类型、class、       │  "改动太大会割裂 Web,   │
│  命名空间、包            │   破坏向后兼容"          │
│  → 几乎是一门新语言       │  → 只想小步修补          │
└────────────────────────┴────────────────────────┘
         分歧无法调和,2008 年 7 月 Oslo 会议
                       │
                       ↓
        ES4 被正式放弃,改走 "Harmony" 路线
        激进特性拆散,务实的部分进入 ES5,
        其余推迟到 ES6 并大幅温和化

ES4 的教训定义了此后所有 ES 版本

在 Web 上,你不能推倒重来。 全世界有数十亿个网页,没有人会为了你的”更好的语言”去重写它们。任何破坏向后兼容的提案,都会因为”它会让现存的 Web 崩溃”而被否决。 这个教训直接塑造了 ES6-ES2015 的策略:永远只增不删、新语法不破坏旧语义(let 不动 varclass 只是语法糖、箭头函数不碰普通函数)。它也是后来 AngularJS→Angular 2 的不兼容重写被视为”反面教材”的历史回响。

③ ES5(2009):务实主义的胜利

ES4 流产后,委员会学乖了。ES5 不碰语法革命,只做”工程师真正需要的修补”:"use strict" 严格模式、原生 JSONArray.prototype.forEach/map/filter、以及关键的 Object.defineProperty——这个 API 后来成了 Vue 2 响应式系统的基石。详见 ES5

④ ES6 / ES2015:分水岭

筹备了 6 年的 ES6 一次性补齐了现代语言该有的一切:let/const、箭头函数、classPromise、模板字符串、解构、Module(ES-Modules)。它是”古典 JS”和”现代 JS”的楚河汉界。详见 ES6-ES2015

⑤ ES2016+:从”大版本”到”年度发布”

ES6 拖了 6 年才发布,惨痛。于是 TC39 改革了流程:从 2016 起改为每年 6 月发布一个小版本,版本号以年份命名(ES2016、ES2017……)。攒大招的时代结束了,从此是持续、可预期的小步快跑

TC39 的 Stage 提案机制(现代 ES 的运作方式)

每个新特性都要经过 5 个阶段的”晋级赛”,每年的 ES 版本 = 当年 6 月所有进入 Stage 4 的提案的合集:

Stage含义
0 Strawperson任何点子
1 Proposal正式立项,有人负责
2 Draft写出规范草案,语法基本定型
3 Candidate规范完成,等待浏览器实现反馈
4 Finished至少两个独立实现 + 通过 Test262,进入下一年标准

关键洞察:Babel 让 Stage 2/3 的提案能被开发者提前用上(转译成 ES5)。这反过来给 TC39 提供了真实世界的反馈,社区成了语言演进的试验场——这是 ES4 闭门造车失败后学到的另一课。


四、带来的新问题 / 副作用

演进的代价

  1. 永久的历史包袱:为了不破坏旧网页,var==typeof null 这些坑被永久冻结在语言里。新特性只能”叠加”,不能”清理”。
  2. 版本碎片化与转译依赖:浏览器实现新特性的速度参差不齐。开发者无法直接用最新语法,必须依赖 Babel 转译 + polyfill,催生了庞大的工具链复杂度(见 2018-2023 工程化时代)。
  3. “年度发布”让认知碎片化:每年都有新语法,初学者很难知道”现在到底该学哪一套”。语言的表面积持续膨胀。
  4. TC39 流程偏慢:为了不重蹈 ES4 覆辙,流程极度谨慎,一些社区急需的特性(如装饰器 decorators)在各 Stage 间徘徊多年。

五、对后续技术的影响(因果链)

Brendan Eich 10 天赶制 JS (1995),被要求"像 Java"
        │
        ├──► 设计仓促 → 一身坑 → 后续标准只能"打补丁"不能"修复"
        │
        ↓
微软抄出 JScript → 语言分叉 → 提交 ECMA 标准化 (1997 ES1)
        │
        ↓
[[ES3]] (1999) 稳定十年 ──► [[jQuery]] 时代的语言地基
        │
        ↓
ES4 野心过大 (静态类型/class/包) ──► 2008 政治分裂流产
        │           │
        │           └──► 教训:"激进破坏兼容必败" ──► 定义了 ES6 的渐进策略
        ↓
[[ES5]] (2009) 务实修补 ──► Object.defineProperty ──► [[Vue]] 2 响应式的地基
        │
        ↓
[[ES6-ES2015]] (2015) 分水岭 ──► class/Promise/箭头函数/模块
        │           │
        │           ├──► [[Babel]] 让 ES6 能在老浏览器跑 ──► 现代前端工具链
        │           └──► [[ES-Modules]] 静态模块 ──► tree-shaking([[Rollup]]) + [[Vite]]
        ↓
ES2016+ 改年度发布 + TC39 Stage 机制
        │
        └──► 社区(Babel)成为语言试验场,演进可预期且持续

历史地位

ECMAScript 的演进史,是一部**“约束下的工程艺术”:在”绝对不能破坏现存 Web”这条铁律下,把一门 10 天赶制的玩具,一点一点修补成支撑全球互联网的现代语言。它最大的遗产不是某个语法,而是一种演进哲学**——只增不删、渐进兼容、让社区先试错。ES4 用一次惨痛流产证明了什么行不通,ES6 之后的每一年都在证明什么行得通。


🔗 时代背景:1995-2005 浏览器时代 | 2013-2018 SPA时代 🔗 版本详解:ES3 | ES5 | ES6-ES2015 | ES-Modules 🔗 相关:Babel | TypeScript | Vue | React | jQuery