🛠️ ES5(2009)

一句话定性

ES5 是 ES4 流产废墟上长出的**“务实主义之花”:它放弃了一切语法革命的野心,只老老实实补齐工程师每天都在用的工具。但它埋下的一颗不起眼的种子——Object.defineProperty**——日后竟成了 Vue 2 整个响应式系统的命门。


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

ES5 发布于 2009 年 12 月,距离上一版 ES3 整整十年。这十年是 JavaScript 的”政治内战期”——ES4 在 2008 年正式流产,委员会元气大伤。ES5 是大家重新坐到一起、达成共识后的第一份成果

它出现的时代背景是 Ajax 时代的高峰:Gmail、Google Maps 证明了”网页可以是应用”,jQuery 已经统治了前端,大型 JS 应用越来越多。开发者迫切需要语言层面的”专业工具”,而不是继续用 ES3 的简陋积木。

ES5 的克制是刻意的

经历了 ES4 的惨败,委员会形成了铁律:绝不破坏向后兼容,绝不做激进语法改革。所以 ES5 几乎没有引入新语法关键字(classlet、箭头函数全都推迟到了 ES6-ES2015)。它做的全是”打磨现有能力”——这正是从 ES4 学到的教训:先活下去,再谈进步。


二、为什么会出现(解决上一代什么痛点)

ES3 时代的开发者(和 jQuery)每天在重复造轮子:

  • 想遍历数组?自己写 for 循环,或用 $.each
  • 想解析服务器返回的 JSON?用 eval()——这是个巨大的安全漏洞(执行任意代码)。
  • 想保护对象属性不被改写?做不到,所有属性都是可写可枚举可删除的。
  • 代码里全是隐式的坏行为(意外创建全局变量、this 指向 window),却没有机制来”开启严格检查”。

ES5 就是来系统性地解决这些”专业开发的日常痛点”的。


三、关键特性 & 为什么重要

"use strict" 严格模式

在文件或函数顶部写一行 "use strict",开启一套更严格的语义:禁止意外创建全局变量、禁止删除不可删除属性、this 在普通函数里为 undefined(而非 window)等。

为什么重要:它是 ES4 教训的完美体现——不能修复旧的坏行为(会破坏旧网页),那就提供一个”选择加入”的新模式,让新代码可以更安全。这种”opt-in 渐进改良”的思路,贯穿了此后所有 ES 版本。

② 原生 JSON.parse / JSON.stringify

为什么重要:在此之前,解析 JSON 要靠 eval(),等于把服务器数据当代码执行——一旦数据被污染就是远程代码执行漏洞。原生 JSON 既安全(C++ 实现)。在 Ajax 数据交换爆发的年代,这是雪中送炭。

③ Array 函数式方法

forEach / map / filter / reduce / some / every / indexOf

为什么重要:它们把”如何遍历”的细节封装起来,让代码从命令式(for (var i...))转向声明式(“我要把每个元素映射成…”)。这是函数式风格在 JS 主流化的起点,也直接影响了后来 React 里”用 .map() 渲染列表”成为肌肉记忆。

Object.defineProperty(最具历史意义的一个)

它能精确定义一个属性的特性,尤其是 getter / setter 访问器:

Object.defineProperty(obj, 'name', {
  get() { /* 读取时触发 */ },
  set(val) { /* 赋值时触发 */ }
})

这个 API 是 Vue 2 响应式系统的命门

Vue 2 的”双向绑定/响应式”魔法,底层就是用 Object.defineProperty 把 data 对象的每个属性改写成 getter/setter:

  • getter 里做依赖收集(谁读了我?)
  • setter 里做派发更新(我变了,通知所有用到我的地方重渲染)

换句话说,没有 ES5 的 Object.defineProperty,就没有 Vue 2 的响应式。这也是为什么 Vue 2 无法检测”新增属性”和”数组下标赋值”——这是 defineProperty 的固有局限,直到 Vue 3 改用 ES6 的 Proxy 才彻底解决。一个 2009 年的 API 决策,框住了一个框架近十年的设计边界。

Function.prototype.bind

永久绑定 this,解决了 JS 最经典的”回调里 this 丢失”问题。在 jQuery 和早期事件回调满天飞的年代,这是救命稻草。


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

ES5 的好东西,大家很多年不敢用

  1. IE6/7/8 不支持,实际可用被推迟多年:ES5 是 2009 年的标准,但 IE8 只部分支持、IE6/7 完全不支持。只要项目还要兼容 IE,你就不能直接用 ES5,得靠 jQuery 或 polyfill(如 es5-shim)垫平。标准发布 ≠ 可以使用,这个时间差是前端的常态。
  2. Object.defineProperty 的局限被框架继承:它无法监听属性的”新增/删除”和数组索引变化。Vue 2 把这个 API 当地基,也就继承了它全部的局限(Vue.set、数组方法重写等 workaround 都是为此打的补丁)。
  3. 没解决根本问题:ES5 没有模块、没有 class、没有 Promise、没有块级作用域。它只是”把 ES3 打磨好了”,真正的现代化要等六年后的 ES6-ES2015
  4. "use strict" 的割裂:严格/非严格两套语义共存,带来了认知负担和一些边界陷阱。

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

ES4 流产 (2008) ──► 教训:"激进必败,务实才能落地"
        │
        ↓
ES5 (2009) 务实修补
        │
        ├──► "use strict" 选择加入 ──► 确立"opt-in 渐进改良"哲学 ──► 影响后续所有 ES 版本
        │
        ├──► 原生 JSON ──► 干掉 eval 安全坑 ──► Ajax 数据交换标准化
        │
        ├──► Array.map/filter/reduce ──► 声明式/函数式风格主流化 ──► [[React]] 用 .map 渲染列表
        │
        └──► Object.defineProperty(getter/setter)
                    │
                    ↓
              [[Vue]] 2 响应式系统的地基(依赖收集 + 派发更新)
                    │
                    ├──► 让 MVVM 双向绑定在 JS 里成为可能
                    └──► 也带来局限(无法监听新增属性/数组下标)
                              │
                              ↓
                       Vue 3 改用 ES6 Proxy 彻底重写响应式

历史地位

ES5 是 JavaScript 从”玩具/库的时代”走向”专业语言”的关键过渡。它本身不性感——没有一个让人眼前一亮的新语法——但它用务实重建了委员会的信任,为六年后 ES6-ES2015 的大爆发铺好了路。而它顺手埋下的 Object.defineProperty,则在无意间成了一整代 MVVM 框架的技术地基。伟大的基础设施,往往是不起眼的。


🔗 时代背景:2005-2013 Ajax时代 | 2013-2018 SPA时代 🔗 版本脉络:ECMAScript演进史 | 上一版 ES3 | 下一版 → ES6-ES2015 🔗 相关:Vue | jQuery | React