跳转到正文

ES1~ES5 ​

参考官方标准:ECMA-262 5.1 Edition
ES1 至 ES5 建立了原型、函数、对象、严格模式和 JSON 等至今仍有效的语言基础。

现代 JavaScript 的原型、闭包、事件循环和动态对象模型,都来自 ES6 之前。理解这一阶段不是为了继续写旧代码,而是为了读懂遗留项目与今天仍然有效的语言机制。

1. 从网页脚本到 ECMAScript 标准 ​

JavaScript 诞生于 1995 年。ECMAScript 把语言核心标准化,浏览器则提供 DOM、事件、网络等宿主能力。

阶段关键变化长期影响
ES1(1997)类型、对象、函数、控制流形成标准建立跨浏览器语言核心
ES3(1999)正则、异常、do...while 等成为早期 Web 2.0 的语言基础
ES4(放弃)过于激进的大型设计未落地社区转向渐进演进
ES5 / ES5.1(2009/2011)严格模式、JSON、数组高阶方法、属性描述符为 ES6 和现代工程化铺路

2. 函数作用域、提升与闭包 ​

var 只有函数作用域,声明会提升;闭包让函数在外层返回后仍可访问词法环境。

javascript
function createCounter() {
  var value = 0;
  return function () {
    value += 1;
    return value;
  };
}

var next = createCounter();
next(); // 1
next(); // 2

经典陷阱是循环中的 var 共享同一个绑定:

javascript
for (var i = 0; i < 3; i += 1) {
  setTimeout(function () { console.log(i); }, 0);
}
// 输出 3、3、3,而不是 0、1、2

现代代码优先使用 let / const 创建块级绑定。维护旧环境时可用 IIFE 为每次循环创建作用域。

3. 原型委托,而不是“没有类” ​

对象通过内部原型链委托属性查找。构造函数和 prototype 只是组织这一机制的经典写法。

javascript
function User(name) {
  this.name = name;
}

User.prototype.greet = function () {
  return "Hello, " + this.name;
};

var ada = new User("Ada");
ada.greet();

ES6 class 提供更清晰的语法,但底层仍建立在原型模型之上。理解原型有助于分析继承、方法共享和 this。

4. this 由调用方式决定 ​

普通函数的 this 不是按定义位置静态绑定,而取决于调用方式:方法调用、显式 call/apply、构造调用或默认调用。

javascript
var account = {
  owner: "Lin",
  showOwner: function () { return this.owner; }
};

var detached = account.showOwner;
account.showOwner(); // "Lin"
detached();          // 严格模式下 this 为 undefined

bind(ES5)可以创建固定接收者的新函数;ES6 箭头函数则捕获外层词法 this。

5. ES5:严格模式、JSON 与数组抽象 ​

javascript
"use strict";

var users = JSON.parse('[{"name":"Ada","active":true}]');
var names = users
  .filter(function (user) { return user.active; })
  .map(function (user) { return user.name; });
  • 严格模式禁止部分易错行为,并让静默失败变成异常。
  • JSON.parse / JSON.stringify 提供标准数据交换。
  • forEach、map、filter、reduce、some、every 把集合变换提升为语言常用范式。
  • Object.create、defineProperty 和属性描述符让对象模型更精确。

6. 回调、事件循环与 Ajax ​

浏览器把计时器、DOM 事件和网络交给宿主环境;回调完成后进入任务队列,主线程空闲时再执行。

javascript
button.addEventListener("click", function () {
  requestData("/api/lessons", function (error, lessons) {
    if (error) {
      showError(error);
      return;
    }
    renderLessons(lessons);
  });
});

多层错误优先回调容易形成“回调金字塔”。Promise 与后来的 async / await 改善了组合方式,但事件循环模型没有消失。

7. ES6 之前的模块化方案 ​

语言没有标准模块时,常用 IIFE 暴露有限 API:

javascript
var lessonStore = (function () {
  var lessons = [];
  return {
    add: function (lesson) { lessons.push(lesson); },
    all: function () { return lessons.slice(); }
  };
}());

随后出现 CommonJS、AMD、UMD 等生态方案。ES Modules 最终把静态 import / export 纳入语言与浏览器平台。

8. 阅读遗留代码的迁移原则 ​

  1. 先补测试,确认隐式类型转换、this 和异步顺序。
  2. 将全局变量收进模块边界。
  3. 谨慎把 var 替换为 let / const,检查提升和循环闭包行为。
  4. 用 Promise 包装回调 API,再逐步引入 async / await。
  5. 不要机械把原型方法改成类;先确认继承与动态扩展约定。

下一阶段:ES6:现代 JavaScript 奠基。

版本信息与迁移 ​

  • 发布时间 / 标准时间: 1997–2009 年(ES1 至 ES5)
  • 维护状态: 截至 2026-08-27,以页面所链接的官方生命周期或规范状态为准
  • 运行时或平台基线: ECMAScript 标准、Node.js/V8 版本、模块系统与依赖运行时要求

迁移影响: 升级前核对 Node.js 官方迁移说明、V8 行为、OpenSSL、CommonJS/ESM 边界和原生扩展 ABI;浏览器代码还要按目标引擎矩阵回归。

版本确认 ​

bash
node --version
node -p "process.versions"

资料核对日期:2026-08-27。

Released under the MIT License.