跳到主要内容

2015 年后 ECMAScript 标准的更新转为年度发布模式,每年更新新的语言特性。

ES1

1995 年,JavaScript 由 Netscape 的工程师 Brendan Eich 发明,最初命名为 Mocha,后改为 LiveScript,最终定名为 JavaScript(为了借助 Java “一次编写,到处运行” 的热度推广,Netscape 与 Sun 达成合作,在 1995 年 12 月将其正式命名为 JavaScript)。

1997 年 6 月,JavaScript 被提交给了欧洲计算机制造商协会(ECMA)进行标准化,该组织发布了第一个版本 ECMAScript 标准(ES1)。

1. 基本语法与结构

  • 变量声明:
    • 使用 var 关键字声明变量。仅支持函数作用域,没有块级作用域
    • 允许重复声明
    • 存在“变量提升”(声明会被提升到作用域的顶端,赋值保留在原位置)
  • 数据类型
    • 原始类型:NumberStringBooleannullundefined
    • 复合类型:Object(也包括数组、函数等)
    • 所有的数字均为双精度浮点数,没有单独的整数类型
  • 运算符:支持
    • 算术运算符(+-*\/%
    • 比较运算符(==!=<><=>=
    • 逻辑运算符(&&||!
    • 赋值运算符(=+=-=*=
    • 其他运算符(typeofinstanceof,
  • 控制结构:包含基本的流程控制语句,如
    • 条件语句:if...elseswitch
    • 循环语句:whiledo...whilefor
    • 跳转语句:breakcontinue
  • 注释:支持单行注释(//)和多行注释(/* */

2. 函数

ES1 确立了“函数是一等公民”的核心特性:

  • 使用 function 关键字定义函数
  • 支持函数声明和函数表达式
  • 可以作为参数传递或从其他函数返回
  • 拥有闭包的基本能力,但由于当时使用场景有限,这一特性并没有被广泛利用

3. 对象

  • 对象的创建: 可以通过对象字面量 {} 或构造函数(new Object())来创建
  • 原型机制:ES1 引入的是基于原型的继承机制。每一个对象都有一个内部属性 [[Prototype]] (在大多数实现中可通过 __proto__ 访问),用于实现继承。这是与基于类的传统面向对象语言(如 Java )的根本区别
  • 内置对象:提供了核心的内置对象,如 ObjectFunctionArrayStringBooleanNumberDateRegExpError
  • 属性操作:通过 .[] 访问属性;支持动态添加、修改、删除属性(delete 关键字)
  • this 关键字:在对象方法中,this 指向当前调用方法的对象;全局函数中 this 指向全局对象

4. 数组

  • 数组的创建:支持数组字面量([元素1, 元素二, ...]) 和 new Array() 构造函数
  • 索引访问:通过数字索引(从 0 开始)访问属性元素,通过 length 属性获取/修改数组长度
  • 基础方法:提供 toString()valueOf() 等简单方法

5. 内置方法与全局对象

  • 全局对象:在浏览器中通常是 window 对象,在 Node.js (额,Node.js 是 2009 才出现的产物,可能是逻辑问题,放在这里做了比较)等环境中是 global。它包含了全局函数如 isNaN()isFinite()parseInt()parseFloat()
  • Math 对象:提供数学常数和函数,如 Math.PIPath.min()Math.random()
  • 基本方法:字符串、数组提供了一些基础方法,例如 String.prototype.lengthArray.prototype.lengthString.prototype.charAt()Array.prototype.push() (部分方法可能在早期实现中不一致)

6. 错误处理

  • 支持 try...catch...finally 语句进行异常捕获和处理
  • 定义了基本的错误类型,如 ErrorSyntaxErrorTypeError

7. 重大意义

  • 结束了浏览器脚本语言的混乱,为 AJAX(1998 年)、jQuery(2006 年)等技术奠定基础
  • 确立了 JavaScript 的设计哲学
    • 动态类型:变量类型在运行时确定(额,好像 ES17 之后要变天了)
    • 函数一等公民:函数可以作为参数传递或返回值,支持高阶函数模式
    • 原型继承:尽管 ES6 引入了 class 语法糖,但底层仍依赖 ES1 的原型链机制
  • 推动了 Web 的开发标准化

8. 先天不足

  • 功能缺失
    • 无原生异常处理:try-catch 机制到 ES3 才真正完善,ES1 调试依赖开发者自行实现
    • 无严格模式:变量提升、全剧作用域污染等问题需手动规避
    • 无模块化支持:代码组织依赖全局变量或命名空间模式
  • 浏览器实现差异:早期浏览器对 ES1 标准的实现存在不一致。例如, IE4 对 array 方法支持不完整,导致浏览器兼容性
  • 设计缺陷
    • 原型链隐式性:开发者需深入内部方法(如 )才能操作对象继承
    • 活动对象模式: ES1 的作用域机制通过活动对象(AO)实现,但边界情况下(如 Object.prototype 属性继承)可能导致意外行为

ES2

1998 年 6 月,推出了 ECMAScript 2.0 标准,为 ECMAScript 1 进行了进一步的规范化和错误修正。

ECMAScript 2nd Edition 并没有新的语言功能或特性,而是为了使 ECMAScript 标准与国际标准化组织(ISO/IEC)的规范保持一致,特别是 ISO/IEC 16262 标准。

主要内容

  • 格式与结构的调整:为了符合 ISO 的文档格式要求,对标准文档的章节结构、编号和排版进行了调整
  • 澄清与修正:对 ES1 标准中一些模糊或可能出现歧义的表述进行了澄清和修正,使规范的描述更加准确和严谨
    • 明确 typeof null 返回 object 的行为,避免不同引擎的理解偏差
    • == 的类型转换逻辑补充了更多的规则,减少了不同实现中“隐式转换”的不一致
    • 细化了 arguments 对象的行为描述
    • 明确了 function 关键字与标识符的空格要求
    • method (方法)统一表述为 property(属性)或 function(函数)
  • 错误修复:修正了 ES1 标准文档中发现的一些非技术性错误和笔误
  • 国际化支持:增加了对 Unicode 字符集的明确引用(在 ES1 中已支持),强调字符串处理需兼容多语言模型,为后续国际化特性(如 ES3 的 String.prototype.localeCompare() )铺路

ES3

1999 年 12 月,发布了 ECMAScript 3 版本,这一版本为 JavaScript 的发展奠定了坚实的基础,引入了正则表达式、异常处理、更严格的错误定义、字符串处理改进等新功能特性。

2005 年,出现了 Ajax(Asynchronous JavaScript and XML),这种技术使得 Web 应用可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页内容。这极大地改善了用户体验,推动了 Web 2.0 时代的到来。

1. 正则表达式

ES3 正式引入了对正则表达式的一等公民的支持。使得复杂的字符串验证、搜索和替换变得高效且简洁,是表单验证、文本处理等场景的基石

提供了:

  • 字面量语法/pattern/flags
  • 构造函数new RegExp(pattern, flags)
  • String 方法支持:新增了 match()replace()search()split() 等方法来利用正则表达式进行字符串处理

2. 异常处理

完善了(ES1 缺乏主动抛出错误和详细错误信息的能力)结构化的错误处理机制 try..catch...finally 语句。让开发者可以更优雅的捕获和处理运行时错误,避免程序崩溃,并执行必要的清理工作,显著提高了代码的健壮性和可维护性。

  • throw 语句:允许主动排除异常(可抛出任意类型值,推荐抛出 Error 对象)
  • Error 对象扩展Error 实例新增 message 属性(储存错误描述),便于捕获时获取详细信息
try {
// 可能出错的代码
throw new Error('莫抛错,抛错必被捉');
} catch (error) {
// 捕获并处理错误
console.error(error);
} finally {
// 无论是否出错都将执行的代码
}

3. switch 语句

(等等,不是说 ES1 就有这玩意么)

引入了 switch 语句,用于基于不同的条件执行不同的代码块。

  • 支持 casedefaultbreak 等关键字

为多分支选择提供了比 if...else if...else 更清晰,更高效的语法结构

4. do...while 循环

新增了 do...while 循环语句,确保循环体至少执行一次

do {
// 循环体
} while (condition);

5. for...in 循环

新增 for...in 循环,用于遍历对象的可枚举属性(包括原型链上的属性)。它解决了早期“通过 for 循环遍历对象属性”的繁琐问题(需使用 hasOwnProperty() 判断属性是否为对象自身所有),成为现代 JavaScript 中操作对象的核心循环结构。

const role = {
name: 'Tom',
age: 86,
species: 'cat',
};

for (let prop in role) {
if (role.hasOwnProperty(prop)) {
console.log(prop.concat(': ').concat(role[prop]));
}
}

6. ==!= 运算符改进

规范了相等(==)和不等(!=) 运算符的类型强制转换(Type Coercion)行为。

7. new 运算符的改进

增强了 new 运算符的语义,使其创建对象的过程更加明确可控。为基于构造函数的面相对象编程模式提供了更可靠的基础。

8. 内置对象的扩展和增强

  • String 对象:新增了
    • charAt():查找给定字符在字符串的索引下标
    • charCodeAt():查找给定字符在字符串的索引下标
    • indexOf():查找给定子串在字符串的位置
    • lastIndexOf()
    • slice()
    • substring()
    • toLoverCase()
    • toUpperCase()
  • Array 对象:新增了
    • concat()
    • join()
    • pop()
    • push()
    • reverse()
    • shift()
    • slice()
    • sort()sort() 还支持传入自定义的比较函数
    • splice()
    • unshift()
  • Date() 对象:增强了日期的处理能力,提供了更精准的毫秒级时间操作方法
  • Function 对象length 属性被标准化,表示函数期望的参数个个数
  • 全局对象isFinite()isNaN() 函数被明确定义和标准化

9. 函数和 this 的增强

ES3 强化了函数的灵活性,尤其是 this 执行的控制:

  • call()apply() 方法:允许调用函数时执行 this 指向,解决了函数在不同上下文执行时的 this 绑定问题
  • arguments 对象完善:明确 arguments 与函数的“动态绑定”(修改了 arguments[i] 会同步修改对应参数,反之亦然),但后续 ES5 严格模式取消了这一特性

10. 语法和语义的澄清

对 ES1 中模糊或有歧义的语法和语义进行了大量的澄清和修正,提高了标准的严谨性,较少了不同浏览器直接的差异,促进了跨平台兼容性。

11. 争议和局限性

  • with 语句的争议:ES3 引入了 with (如 with(obj) { console.log(a); }),简化对象属性的访问,但由于 with 语句会破坏作用域链的可预测性(导致变量解析歧义),ES 5 中将其标记为“不推荐使用”,并在 ES6 的严格模式下完全禁用
  • 函数提升的副作用:ES3 延续了 ES1 的函数提升机制,导致了变量提升与函数提升的交互复杂。如,foo(); function foo(){} 可执行,而 foo();var foo = function() {} 却报错不可执行
  • 性能优化缺失:ES3 未针对循环、对象访问等高频操作性能优化建议(如 for...in 遍历数组的性能问题),导致早期 JavaScript 代码效率低下。这一问题直到现代浏览器(如 Chrome、Firefox )通过 JIT(即时编译)优化才得到缓解

ES4

由于种种原因,ES4 并没有。但是许多特性在后来的 ES5 和 ES6 中得到了实现。

ECMAScript 4th Edition(ES4) 是在 1999 年发布 ES3 后,微软(.NET 平台)、Mozilla(Firefox)、Adobe(Flash 平台的 ActionScript 与 JavaScript 同源,希望统一标准) 等公司希望将 JavaScript 打造成一门可以与 Java、C# 竞争、适合大型应用开发的企业级语言,试图从一门动态脚本语言转变成一门更严谨、更适合大规模开发的静态类型语言

信息

俗话说的好,步子迈得太大,容易扯着蛋

1. 强类型系统(Strong Typing)

  • 引入类似 Java/C# 的静态类型声明,允许变量、函数参数和返回值执行数据类型
var name: String = 'Tom';

function add(a: int, b: int): int {
return a + b;
}

2. 类 (Classes)

计划引入基于类的继承语法,包括 classextendspublicprivateprotected 等关键字,这将取代当时主流的基于原型的构造函数模式。

3. 模块化 (Modules)

提出了一套完整的模块系统,用于代码的组织、封装和依赖管理,支持 importexport

4. 包(packages) 和命名空间(Namespaces)

为了管理大型代码库,引入了 packagenamespace 概念,以避免全局污染和命名冲突。

5. 丰富的集合类型

计划添加如 ListDict(字典)、Set 等新的内置数据结构。

6. 迭代器(Iterators)和生成器(Generators)

虽然最终在 ES6 上实现,但这一概念最早在 ES4 上讨论中被提出。

7 其他高级特性

  • 泛型(Generics)
  • 多重继承(Multiple Inheritance)
  • 字符串模版(String Interpolation)
  • 更大的元编辑能力

8. 失败的原因

  • 复杂性过高: ES4 提案过于庞大和复杂,学习曲线陡峭,违背了 JavaScript 原有的简洁和灵活性
  • 社区分裂: JavaScript 社区内部存在严重分歧。以 Yahoo!、Google 和 Opera 为代表的公司(尤其是 Brendan Eich,JavaScript 的创始者)强烈反对这种激进的变革。他们认为这样会使 JavaScript 变得臃肿,失去其作为“网络胶水语言”(Web glue language)的轻量和敏捷特性
  • 向后兼容性的担忧:如此巨大的变更几乎不能保证与现有海量 JavaScript 代码完全兼容
  • 实现难度大:为浏览区实现这么一个复杂的引擎需要巨大的工程投入
  • 路线之争:形成了两派:一派(ES4 支持者)主张大步前进;另一派主张小步快跑,先解决 ES3 中的问题并添加少量实用的新特性

9. 虽败犹荣

ES4 项目本身是失败的,但它的影响确是深远且积极的:

  • 催生了 ES3.1/ES5:
    • 反对 ES4 激进路线的一方提出了替代方案---“ES3.1”,即只进行必要的、不破坏的兼容性改进
    • 这个方案最终胜出,并发展为 ECMAScript 5th Edition(ES5),于 2009 年发布。 ES5 包含了 strict modeJSON 支持、ArrayforEach/map/filter 等方法,以及对对象属性更精细控制(Object.defineProperty)等实用改进
  • 许多思想在 ES6+ 中复活
    • 类(classes):ES6(2015)引入了 class 语法糖,虽然底层仍是基于原型,但提供了熟悉的类式语法
    • 模块化(Modules):ES6 正式引入了 import/export 模块系统
    • let/const: 提供了块级作用域,解决了 var 的问题
    • 迭代器与生成器:ES6 实现了这些特性
    • 箭头函数、结构赋值、字符串模版:这些现代 JS 特性都可以追溯到 ES4
    • TypeScript 的灵感来源:微软后来推出的 TypeScript 语言,可以看作是“实现了 ES4”。它为 JavaScript 添加了可选的静态类型、类、模块等特性,完美契合了当年的 ES4 的愿景
提示

ES5

2008 年,谷歌发布了 Chrome 浏览器,内置了 V8 JavaScript 引擎。V8 引擎极大地提高了 JavaScript 的执行速度,这促进了更复杂的 Web 应用的开发。

2009 年 12 月,发布了 ECMAScript5 ,主要提出了严格模式(use strict)和 JSON 支持以及数组新方法(forEachmapfilterreducesomeevery)、新的对象方法(Object.createObject.definePropertyObject.keys)、新的原生方法和增强的原型链。

2009 年,Ryan Dahl 推出 Node.js ,这是一个开源、跨平台的运行环境,允许开发者使用 JavaScript 来编写服务器端代码。

1. 严格模式(Strict Mode)

通过在脚本或函数的顶部添加 "use strict"; 指令启动。

  • 捕获错误:将原本静默失败的错误(如给未未声明的变量赋值)变成显式的 ReferenceError
  • 禁用危险语法:禁止使用 witheval 影响外部作用域等容易引发问题的特性
  • 防止意外全局变量:在非严格模式下, x = 1; 会创建全局模式;严格模式下,这会抛出错误
  • this 绑定安全:在非法调用时的函数中,this 不再指向全局对象(window),而是 undefined,避免了全局污染
  • 禁止删除不可删除的属性:如 delete Object.prototype 在非严格模式下静默失败,严格模式下直接报错
  • 禁止重复参数名function fn (a, a) { } 在非严格模式下允许(后一个会覆盖前一个),严格模式下会报错
  • 提高性能:引擎可以进行更多优化,因为严格模式下的代码行为更可预测

2. 内置对象的扩展与方法增强

  • Array 对象
    • 迭代方法:新增了 forEach()map()filter()some()every()reduce()reduceRight() 等方法。这些方法支持函数式编程风格,无需修改原数组即可进行遍历、转换和聚合,代码更简洁、更易读
    • 查找方法:indexOf()lastIndexOf() 用于查找元素在数组中的引用
  • String 对象
    • trim(): 移除字符串首尾的空白字符(空格、字符串、换行符等),解决了常见的字符串处理痛点
  • Object 对象
    • Object.create(proto, [propertiesObject]):创建一个对象,并指定其原型。这是实现原型继承的更直接、更清晰的方式
    • Object.defineProperty(obj, prop, descriptor)/Object.defineProperties(obj, props): 允许精确控制对象的属性的特征,如 valuewritableenumerableconfigurable 。这是实现数据绑定、响应式的基础
    • Object.keys(obj):返回一个由自身对象所有可枚举属性名组成的数组
    • Object.getOwnPropertyNames(obj):返回一个由对象自身属性名(包括不可枚举属性)组成的数组
    • Object.getOwnPropertyDescriptor(obj, prop):获取指定属性的完整描述符对象
    • Object.seal(obj):密封对象,阻止添加新属性和删除现有属性,但允许修改现有属性的值
    • Object.freeze(obj):冻结对象,最严格的保护,对象及其属性都不可变
    • Object.preventExtensions(obj):阻止向对象添加新属性

3. JSON 原生支持

内置了 JSON 对象,提供了 JSON.parse()JSON.stringify() 两个方法。使得数据的序列化和反系列化变得极其简单、高效和安全。这极大的促进了 AJAX 技术和 RESTful Web API 的普及,是 Web 2.0 时代的关键推动力。

const jsonStr = '{"name":"Tom","age":86}';

/** 转化为 JSON 对象 */
const obj = JSON.parse(jsonStr);

// true
console.log(jsonStr == JSON.stringify(obj));

4. 函数上下文的绑定

使用 Function.prototype.bind(thisArg[, arg1[, arg2[, ...]]]) 创建一个新的函数,该函数的 this 值将永久绑定在指定 thisArg 对象,并可以预设部分参数。

完美解决了 this 绑定混乱的经典问题,尤其是在事件处理、回调函数和异步编程中。bind 方法是现在 JavaScript 中管理函数执行上写文的核心工具

5. Getter/Setter 属性

允许使用 getset 关键字定义对象的访问器属性。当读取或设置属性时,会自动调用相应的 getter 和 setter 函数。

const obj = {
_value: 86,
get value() {
return this._value;
},
set value(value) {
this._value = value;
},
};

6. 保留字使用放宽

可以使用某些保留字(如 classdefault )作为属性名而无需使用引号,提高了代码的灵活性。

7. Date.now()

静态方法,返回当前时间的时间戳(毫秒值),比 new Date().getTime() 更简洁高效。

8. Array.isArray(arr)

可靠的返回一个值是否为数组。在此之前, instanceof Array 在多窗口/框架下可能失效。

9. 分析

优点:

  • 稳健可靠:所有新增的功能都经过深思熟路,旨在解决实际问题,且不破坏现有代码
  • 实用性极强strict modeJSONArray 的迭代方法、bind 等特性都是开发者日常使用中高频使用的“刚需”功能
  • 推动现代化:为现代 Web 开发(如单页面应用,AJAX )提供了必要的语言支持
  • 广泛兼容: 迅速被所有现代浏览器支持,成为事实上的标准

ECMAScript 5 是 JavaScript 成熟的标志。它通过引入 strict mode、原生 JSON 支持、强大的 ObjectArray API 和 bind 方法,极大地增强了语言的能力、安全性和开发效率。

ES5 的设计哲学-- 渐进式改进、注重实用性和向后兼容 -- 确保了它的成功。在 ES3 的基础上增补了核心功能空白(如 JSON、严格模式、精细的对象控制),同时为 ES6 的“爆发式增强”奠定了基础。也使得其成为 JavaScript 发展史上的“里程碑版本”。

ES5.1

2011 年 6 月,作为 ES5 的小更新,进行了了一些规范上的调整和错误的修正。