0. 前言

1、名称由来

说起JavaScript相关的历史,还得追溯到计算机及其编程语言诞生之初的那段时间。

在1959年,欧洲的计算机产业已经出现蓬勃发展的迹象了,现代意义的计算机也越来越多地开始在科研机构,政府等社会场所被使用,使用的人多了,计算机操作技术实现标准化就被推上了日程,例如编程,以及输入和输出代码规范等。

行业标准对于行业发展的重要性不言而喻。为了协调标准制定工作,欧洲数据处理领域历史最悠久的公司(Compagnie des Machines Bull、IBM World Trade Europe Corporation 和 International Computers and Tabulators Limited)的负责人向所有已知的计算机发出了联名信。欧洲制造商邀请这些公司派代表参加会议。这次会议于 1960 年 4 月 27 日在布鲁塞尔举行;决定成立一个制造商协会,称为欧洲计算机制造商协会(European Computer Manufacturers Association)或简称 ECMA,并提名了一个委员会来准备该协会的成立并制定章程和规则。随后的 1961 年 5 月 17 日,协会正式成立。

这便是ECMA这个名字的来源。

ECMA走向全球后,在1994 年更名为:Ecma International。其商标“ECMA”由于历史原因被保留了下来,沿用至今。

2、ECMA-262标准,梦开始的地方

EMCA标准容纳了大量通信、计算机及其相关行业的标准规范。我们找一下本文的主角。

官网中扒一张图:

image.png

可以看到,第262号标准又叫ECMAScript,是ECMA定义的一套脚本语言编程规范。

ECMAScript 通常缩写为 ES。

正是因为有这个标准的出现,才有了 JavaScript 的蓬勃发展!感谢大佬赏饭吃!!

ECMA-262是一种规范(官网中可以查到各个版本的PDF提案),自然会有满足这种规范的具体的语言被创造出来。最著名的就是JavaScript (现在商标属于Oracle),在1995年由Netscape公司的Brendan Eich,在Netscape导航者浏览器上首次设计实现而成。因为Netscape与Sun合作,Netscape管理层希望它外观看起来像Java,因此取名为JavaScript。但实际上它的语法风格与Self及Scheme较为接近。其设计思路如下:

  1. 借鉴 C 语言的基本语法。
  2. 借鉴 Java 语言的数据类型和内存管理。
  3. 借鉴 Scheme 语言,将函数提升到“第一等公民”(first class)的地位。
  4. 借鉴 Self 语言,使用基于原型(prototype)的继承机制。

JavaScript的是一门动态弱类型、基于原型的一种解释性计算机脚本语言。

在没有 JavaScript 的年代,一些简单的表单验证(如常见的 密码复杂度验证)都是由服务端负责的,而且当时的网络速度是非常慢的,这种验证方式会导致网站的响应速度变得更慢,于是便有了这门语言的诞生。

其次还有微软自研的一套语言,叫JScript,其声称完全遵循ECMA-262规范。下面列举一下二者的区别:

特点JavaScriptJScript
运行平台客户端,服务端客户端,服务端
解释环境Netscape Livewire、V8(Chrome + node)、TraceMonkey等WSH、ASP、.Net
支持浏览器所有主流浏览器主要是IE3.0+
出现时间比较早,甚至早于ECMA-262VBScript竞争失败后的产物

1. JavaScript 1.0 (96年)

发布于1996年,适用于Netscape Navigator2.0浏览器,初步确定了完整的JavaScript的三个构成要素:

  1. ECMAScript(姑且这么叫,1.3版本才正式完全兼容ECMA规范)。JavaScript 的核心部分,它规定了 JavaScript 的语法、类型、语句、 关键字、保留字、运算符和对象。

  2. DOM(Document Object Model)。通过把整个页面映射成一个树结构的文档,提供 了一套可以访问 HTML 和 XML(eXtensible Markup Language)节点的 API(Application Programming Interface),开发者可以利用它轻松地删除、添加、替换或修改任何节点。

  3. BOM(Browser Object Model)。提供了访问浏览器窗口的方法,开发者可以控制浏 览器窗口进行一些诸如移动窗口之类的操作。BOM 部分的有关定义,零散分布在各种标 准中,主要位于 HTML 标准。其他比如 WebRTC 标准等内也定义了一些接口。

1.0里有一些以后很少用的冷门特性。比如函数不但有call,apply方法,还有name和length,还有arguments, caller(在1.2版移除);Arguments是个对象而不是数组;对象可以用数字下标访问属性;没有===的强类型判定;对不支持script标签的浏览器做特殊注释兼容等。

2. JavaScript 1.1(96年)

发布于1996年下半年,适配了Netscape Navigator3.0 和 IE3.0。完善数组对象和方法。

3. JavaScript 1.2(97年)

发布于1997年,适配了Netscape Navigator4.0,但不支持 IE 环境。增加了===的判断方式。

4. JavaScript 1.3 与 ECMAScript 1/2(98年)

发布于1998年。前边说JavaScript出现时间早于ECMA-262,指的就是这个版本的事情。这一年,ECMA标准化了JavaScript1.1的基本特性,同时JavaScript也升级到1.3,并添加了一些新特性(没有标准化switch语句和正则表达式)。至此,JavaScript才逐步遵循ECMA规范进行升级换代。

ECMAScript 2标准是对v1的一个维护版本,只添加了说明,也在同一年发布。

5. JavaScript 1.4(99年)

适用于Netscape server的专用版本。

6. JavaScript 1.5 与 ECMAScript 3(00年)

发布于2000年底,开始支持 Mozilla Firefox 和 Opera 浏览器,并标准化了switch语句、异常处理( try/catch)和正则表达式。

7. JavaScript 1.6(05年)

2005年发布。逐步增加了数组的扩展方法、增加了Array和String泛型、支持XML扩展(E4X)。开始支持Safari 3.0。同年,Ajax技术发布。

新增的数组扩展如下(部分扩展在ES5中逐步规范化):

新增扩展描述
indexOf()返回指定项首次出现的index
lastIndexOf()返回指定项最后一次出现的index
every()在数组中的每一个项运行一个函数。如方法可用遍历每一个项都返回的true,则返回true
filter()在数组中的每一个项运行一个函数,并将这个函数返回true的项作为一个数组返回
forEach()在数组中的每一个项运行一个函数
map()在数组中的每一个项运行一个函数,并将所有的结果作为数组返回
some()在数组中的每一个项运行一个函数,如果这个方法访问的任何一个项返回true,则返回true

泛型(非TS的那种)使用:

function isLetter(character) {  
  return (character >= "a" && character <= "z");  
}  

// 在字符串中使用数组的方法
if (Array.every(str, isLetter))  
  alert("The string '" + str + "' contains only letters!");

8. JavaScript 1.7(07年)

2007年发布。新特性如下:

  • 学习了Python的语法,并引入了Pythonic generators(generator函数)、
  • 引入解构赋值
  • Iterators(迭代器)
  • let 声明

这仍然是ES3的内容,不要认为是ES6才有的。

  • 开始支持 Google Chrome1.0。

9. ECMAScript 4

2008年被废弃的标准。死亡原因

10. JavaScript 1.8 (08-10年) 与 ECMAScript 5 (09年)

包含很多patch版本。

2008年发布 1.8.0

新特性:

新特性描述
表达式闭包见下面代码
生成器表达式个新特性使你可以使用类似数组概念的语法来创建一个独立的生成器句柄,见代码

表达式闭包:

// JavaScript 1.7 以及更老的版本:
function(x) { return x * x; }

// JavaScript 1.8:
function(x) x * x;

生成器表达式

// 使用1
let it = (i + 3 for (i in someObj));
try {
    while (true) {
        document.write(it.next() + "<br>\n");
    }
} catch (err if err instanceof StopIteration) {

    document.write("End of record.<br>\n");
}

// 使用2
function handleResults( results ) {
    for ( let i in results )
    ...
}
handleResults( i for ( i in obj ) if ( i > 3 ) );

同年发布 1.8.1

新特性:

新特性描述
Object.getPrototypeOf()返回指定对象的原型对象,见示例
Firefox 3.5 原生支持 JSON-
String对象新增方法String   增加  trim() ,   trimLeft() , 和   trimRight() 
其他一些次要更新-

2009年发布 1.8.2

一些次要更新。

2010年发布 1.8.5,并遵循ECMAScript 5 (2009年发布)规范

一次大的更新,将之前JS各个版本的方法进行统一汇总整理,并新加入一批API,一起写入规范,使得ES和JS的贴合程度更深。

新特性描述
添加了“严格模式”use 'strict'
规范this关键字-
对 JSON支持-
字符串方法见下列表
数组方法见下列表
各种对象方法见下列表
  • 严格模式
  1. 不允许省略var定义变量
  2. 不允许函数形参同名
  3. 不允许普通函数中的this代表window
  • this规范
  1. 全局this、普通函数的this 、 自调用函数的this都代表window
  2. 事件函数中的this代表事件源
  3. 对象方法中的this代表当前对象
  4. 普通函数被谁调用,函数中this指向谁
  • ES5 新增数组方法/规范(部分方法js1.6中已经有过实现,在ES5正式写入规范)
  1. Array.isArray()
  2. Array.forEach()
  3. Array.map()
  4. Array.filter()
  5. Array.reduce()
  6. Array.reduceRight()
  7. Array.every()
  8. Array.some()
  9. Array.indexOf()
  10. Array.lastIndexOf()
  • ES5新增字符串规范
  1. String.trim()
  2. charAt()
  3. 可对字符串进行属性访问
  4. 允许多行字符串,每一行使用反斜杠结尾
  5. String.fromCharCode() 用于从 Unicode 码点返回对应字符
  • ES5 新增各种对象方法
  1. JSON.parse()
  2. JSON.stringify()
  3. Date.now()
  4. 属性 Getter 和 Setter
  5. 新的对象属性和方法规范,见下表
新的对象属性和方法规范描述
Object.defineProperty(object, property, descriptor)添加或更改对象属性
Object.defineProperties(object, descriptors)添加或更改多个对象属性
Object.getOwnPropertyDescriptor(object, property)访问属性
Object.getOwnPropertyNames(object)将所有属性作为数组返回
Object.keys(object)将可枚举属性作为数组返回
Object.hasOwnProperty(key)是否为对象自身属性
Object.getPrototypeOf(object)获取对象原型
Object.preventExtensions(object)防止向对象添加新的属性
Object.isExtensible(object)如果可以将属性添加到对象,则返回 true
Object.seal(object)防止更改对象属性(而不是值)对象不可以新增属性和删除 但是可以修改
Object.isSealed(object)如果对象被密封,则返回 true
Object.freeze(object)防止对对象进行任何更改 不可以新增属性和删除也不可修改 完全锁死
Object.isFrozen(object)如果对象被冻结,则返回 true
允许保留字作为属性名称var obj = {name: "Bill", new: "yes"}
  • ES5 语法更改
  1. 对字符串的属性访问 [ ]
  2. 数组和对象字面量中的尾随逗号(JSON除外)
  3. 多行字符串字面量
  4. 作为属性名称的保留字
  • ES5 浏览器支持

Chrome 23、IE 10 和 Safari 6 是第一批完全支持 ECMAScript 5 的浏览器:

Chrome23IE10/EdgeFirefox21Safari6Opera15
compatible_chrome.pngcompatible_ie.pngcompatible_firefox.pngcompatible_safari.pngcompatible_opera.png
2012年9月2012年9月2013年4月2012年7月2013年7月

11. ECMAScript 6 (2015年)

2015年发布ES6,又是一次重大更新:

新的特性和扩展描述
变量声明let: js1.7中已经有过实现,这里重提,说明块级作用域的重要性;const:常量;变量解构赋值let \[a, b, c] = \[1, 2, 3]; let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
幂 (**)指数运算符, Math.pow() ?
默认参数值函数声明时可以制定默认参数
字符串扩展见下面列表
正则扩展见下面列表
数组扩展见下面列表
对象扩展见下面列表
新的数字属性ES6 将以下属性添加到 Number 对象: EPSILON、MIN_SAFE_INTEGER、MAX_SAFE_INTEGER
新的数字方法Number.isInteger() 、Number.isSafeInteger(), Math也新增了17个静态方法
新的全局方法isFinite()、isNaN()
函数扩展1、引入箭头函数:没有自己的this、没有递归,事件绑定,解绑定、没有构造器、不可具名化、书写简单 2、引入rest参数 3、增加Function.prototype.toString()
Symbol新的原始数据类型, 表示独一无二的值
新增数据结构Set和Map
Proxy对象代理,详见阮老师的解释
Reflect为了操作对象而提供的新 API
前端异步策略Promise(通常与ES2017的async一起使用)
迭代器将Iterator 、 for...of 循环 和 Generator函数写入规范
Class声明增加继承、接口等概念
ESModulejs原生支持模块化
新增提案装饰器Decorator、do 表达式、throw 表达式、函数的部分执行、管道运算符、Math.signbit()、双冒号运算符、Realm API、#!命令、import.meta、JSON 模块
新增规格文件-
  • 字符串扩展
  1. 字符串Unicode标识法,并允许直接输入字符
  2. 引入字符串遍历器
  3. JSON.stringify改造
  4. 引入模板字符串、标签模板渲染
  5. 新增一些方法,见下表
字符串方法描述
String.fromCodePoint()可以识别大于0xFFFF的字符
String.raw()返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,往往用于模板字符串的处理方法
codePointAt能够正确处理 4 个字节储存的字符,返回一个字符的码点。
normalize将字符的不同表示方法统一为同样的形式,这称为 Unicode 正规化。
startsWith返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith返回布尔值,表示参数字符串是否在原字符串的尾部。
repeat返回一个新字符串,表示将原字符串重复n次。
at接受一个整数作为参数,返回参数指定位置的字符,支持负索引(即倒数的位置)。
  • 正则扩展
  1. RegExp构造函数增加第二个参数
  2. ES6 出现之前,字符串对象共有 4 个方法,可以使用正则表达式:match()replace()search()split()。ES6中RegExp集成了这四个方法。
  3. u修饰符
  4. 新增RegExp.prototype.unicode 属性
  5. 新增RegExp.prototype.sticky 属性
  6. 新增RegExp.prototype.flags 属性
  • 数组扩展
  1. 引入扩展运算符
  2. Array.from()
  3. Array.of()
  4. 实例方法:copyWithin()
  5. 实例方法:find() 和 findIndex()
  6. 实例方法:fill()
  7. 实例方法:entries(),keys() 和 values()
  8. 数组的空位定义
  9. Array.prototype.sort() 的排序稳定性问题:常见的排序算法之中,插入排序、合并排序、冒泡排序等都是稳定的,堆排序、快速排序等是不稳定的。不稳定排序的主要缺点是,多重排序时可能会产生问题。在ES2019才解决。
  • 对象扩展
  1. key和变量是同一个单词时,可简写
  2. 属性名表达式写法:obj['a' + 'bc'] = 123;
  3. 方法有name属性
  4. Object.assign()
  5. 对象属性遍历方式:for...in、Object.keys(obj)、Object.getOwnPropertyNames(obj)、Object.getOwnPropertySymbols(obj)、Reflect.ownKeys(obj)
  6. super关键字
  7. 对象扩展...
  8. Object.is():ES5 比较两个值是否相等,只有两个运算符:相等运算符(==)和严格相等运算符(===)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0。JavaScript 缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等。
  • ES6 浏览器支持

Safari 10 和 Edge 14 是首先完全支持 ES6 的浏览器:

Chrome 58Edge 14Firefox 54Safari 10Opera 55
compatible_chrome.pngcompatible_ie.pngcompatible_firefox.pngcompatible_safari.pngcompatible_opera.png
Jan 2017Aug 2016Mar 2017Jul 2016Aug 2018

ES6之后没有小数字版本的ECMAScript了,取而代之的是以年份为代号的版本,因为每一年都会有一个版本。网传的ES7、ES8什么的,其实官方没有这种叫法。

12. ECMAScript 2016

2016年发布。

新特性描述
求幂赋值let x = 5; x **= 2; // 结果是 25
Array.prototype.includes-
装饰器动态
  • ES2016 浏览器支持

所有现代浏览器都支持 Array.prototype.includes:

Chrome 47Edge 14Firefox 43Safari 9Opera 34
compatible_chrome.pngcompatible_ie.pngcompatible_firefox.pngcompatible_safari.pngcompatible_opera.png
2015 年 12 月2016 年 8 月2015 年 12 月2015 年 10 月2015 年 12 月

最近的版本快速浏览:

13. ECMAScript 2017

2017年发布。

新特性描述
异步声明async/await
对象支持尾逗号{ a: 1, b: 2, }
字符串扩展String.padStart 和 String.padEnd,增加字符串前后缩进
对象扩展Object.values、Object.entries、Object.getOwnPropertyDescriptors()

14. ECMAScript 2018

2018年发布。

新特性描述
异步迭代ES2018引⼊异步迭代器,允许 for...of 循环可以和 await ⼀起使⽤,以串⾏的⽅式运⾏异步操作
Promise扩展Promise.finally()
Rest参数的Spread属性展开运算符:Math.max(...values) // values = [1,2,3,4]
正则表达式命名捕获组ES2018允许命名捕获组使⽤符号?<name>,在打开捕获括号(后⽴即命名
正则表达式反向断言?<= 、?\<!
正则表达式 s 修饰符:dotAll 模式正则扩展
正则表达式Unicode转义正则扩展
  • 异步迭代示例:
// 不起作用
async function process(array) {
  for (let i of array) {
    await doSomething(i);
  }
}

// 起作用了
async function process(array) {
  for await (let i of array) {
    doSomething(i);
  }
}

15. ECMAScript 2019

2019年发布。

新特性描述
字符串扩展String.prototype.trimStart() , String.prototype.trimEnd(),原来的trimLeft和trimRight被废弃
Object.fromEntries()Object.entries的逆运算
数组拍平Array.prototype.flat() , Array.prototype.flatMap()
catch 的参数改为可选可以省略catch绑定的参数和括号
Symbol.description-
JSON Superset 超集即js兼容所有JSON支持的文本。原始的JSON 内容可以正常包含 U+2028行分隔符 与 U+2029段分隔符,而之前版本的ECMAScript 却不行
JSON.stringify() 转化特殊字符修复了对于一些超出范围的 Unicode展示错误的问题
Array.sort变为稳定算法
Function.prototype.toString()增强可以返回注释和空格
String.prototype.matchAll返回一个包含所有匹配正则表达式及分组捕获结果的迭代器

16. ECMAScript 2020

2020年发布。

新特性描述
Promise.allSettled当所有promise都resolve或reject后,返回resolve或reject的结果集合数组
链判断运算符const firstName = message?.body?.user?.firstName || 'default';
空值合并运算符var level = user.level ?? '暂⽆等级';
动态引入import(/test.js).then((module) =>
globalThis对象globalThis 提供了一个标准的方式来获取不同环境下的全局 this 对象(也就是全局对象自身)。不像 window 或者 self 这些属性,globalThis 确保可以在有、无窗口的各种环境下正常工作
引入bigintNumber有取值范围 [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER], 超过这个范围会精度丢失,这就需要大数类型:var bigIntNum = 9007199254740993n;

17. ECMAScript 2021

2021年发布。

新特性描述
Promise.any接收一个Promise数组,只要其中任意一个resolve,便通过,否则拒绝
replaceAll返回⼀个全新的字符串,所有符合匹配规则的字符都将被替换掉
WeakRefs在一般情况下,对象的引用是强引用的,这意味着只要持有对象的引用,它就不会被垃圾回收。只有当该对象没有任何的强引用时,垃圾回收机制才会销毁该对象并且回收该对象所占的内存空间。而 WeakRef 允许保留对一个对象的弱引用,而不会阻止被弱引用的对象被垃圾回收。
数字声明时可增加分隔符const num = 1_000_000_000 //1000000000
新的逻辑运算符和表达式见下面代码
a ||= b
//等价于
a = a || (a = b)
a &&= b
//等价于
a = a && (a = b)
a ??= b
//等价于
a = a ?? (a = b)

18. ECMAScript 2022

2022年发布。

新特性描述
class新特性1、增加private属性, class A { #a = 1 }; 2、增加class的static成员方法
top-level await可以使用type='module'的script标签引入一个js文件,js里使用await获取异步数据
数组实例方法at(index)a = [1,2,3]; const value = a.at(1)
error处理新方式throw new Error('fail', { cause: 123 }); 在catch里获取:catch(e) { console.log(e.cause) }
Object.hasOwn(obj, propKey)同hasOwnProperty,但支持所有对象类型的判断

19. ECMAScript 2023

  • 从头到尾搜索数组:findLast() 、findLastIndex()
  • Hashbang 语法
  • 通过副本更改数组:toReversed()toSorted()toSpliced()with()
  • Symbol 作为 WeakMap 的键

20. 后记

随着ECMAScript版本的更新,文章会持续保持更新~~


参考资料

Was this page helpful?