ECMAScript 2016 年至今的主要版本及重大改进

44 阅读4分钟

从 ES2016(ES7)开始,ECMAScript 每年发布一个版本,每次更新都聚焦于实用的小特性迭代。以下是 2016 年至今的主要版本及重大改进:

ES2016(ES7)- 2016 年

  • Array.prototype.includes

判断数组是否包含某个元素,替代 indexOf(更直观,支持 NaN 判断):

[1, 2, NaN].includes(NaN); // true(indexOf 会返回 -1)
  • 指数运算符( ******

简化幂运算,替代 Math.pow:

2 **3; // 8(等价于 Math.pow(2, 3))

###** ES2017(ES8)- 2017 年 **-Object.values() / Object.entries()

快速获取对象的值数组和键值对数组:

const obj = { a: 1, b: 2 };
Object.values(obj); // [1, 2]
Object.entries(obj); // [['a', 1], ['b', 2]]

-String.prototype.padStart() / padEnd() 字符串补全(常用于格式化,如时间补零):

'5'.padStart(2, '0'); // "05"
'abc'.padEnd(5, '-'); // "abc--"

-** 异步函数(async/await)** 简化 Promise 链式调用,用同步写法实现异步逻辑:

async function fetchData() {
  const res = await fetch('url'); // 替代 .then() 链式
  const data = await res.json();
  return data;
}

-** 共享内存与原子操作(SharedArrayBuffer / Atomics)** 支持多线程共享内存(主要用于 Web Worker 高性能计算)。

###** ES2018(ES9)- 2018 年 - 异步迭代(for-await-of)** 遍历异步数据源(如异步生成器):

async function process() {
  for await (const data of asyncGenerator()) {
    console.log(data);
  }
}

-** 对象展开 / 剩余属性(...)** 扩展对象的复制与合并:

const obj1 = { a: 1 };
const obj2 = { ...obj1, b: 2 }; // 合并对象
const { a, ...rest } = obj2; // 剩余属性:rest = { b: 2 }

-** 正则表达式增强 **- 命名捕获组:/(?\d{4})-/ 可通过 groups.year 获取匹配值

  • 反向断言:/(?<=¥)\d+/ 匹配 ¥ 后的数字(不包含 ¥ 本身)
  • Unicode 转义:\p{Script=Greek} 匹配希腊文字符

###** ES2019(ES10)- 2019 年 **-Array.prototype.flat() / flatMap() 数组扁平化:

[1, [2, [3]]].flat(2); // [1, 2, 3](参数指定深度)
[1, 2].flatMap(x => [x, x*2]); // [1, 2, 2, 4]

-String.prototype.trimStart() / trimEnd() 精准去除字符串首尾空白(替代 trimLeft / trimRight)。

-Object.fromEntries() 将键值对数组转为对象(Object.entries 的逆操作):

Object.fromEntries([['a', 1], ['b', 2]]); // { a: 1, b: 2 }

-Symbol.prototype.description 获取 Symbol 的描述字符串:

const sym = Symbol('desc');
sym.description; // "desc"

###** ES2020(ES11)- 2020 年 - 可选链(?.)** 安全访问嵌套对象属性,避免 Cannot read property 'x' of undefined 错误:

const name = user?.address?.city; // 若 user 或 address 为 null/undefined,返回 undefined

-** 空值合并运算符(??)** 处理默认值(仅在左侧为 null/undefined 时生效,区别于 ||):

const score = 0 ?? 60; // 0(若用 || 会返回 60)

-** 动态导入(import())** 按需加载模块(返回 Promise):

button.addEventListener('click', () => {
  import('./module.js').then(module => module.doSomething());
});

-BigInt 类型支持任意精度整数(解决 Number 最大安全值限制):

const big = 9007199254740993n; // 末尾加 n 表示 BigInt

-globalThis 统一全局对象引用(浏览器中是 window,Node.js 中是 global,统一为 globalThis)。

###** ES2021(ES12)- 2021 年 - 逻辑赋值运算符(||= / &&= / ??=)** 简化赋值逻辑:

// 等价于:if (!a) a = b
a ||= b; 
// 等价于:if (a) a = b
a &&= b;
// 等价于:if (a === null/undefined) a = b
a ??= b;

-String.prototype.replaceAll() 替换字符串中所有匹配项(无需正则全局标志 g):

'aaa'.replaceAll('a', 'b'); // "bbb"

-** 数字分隔符(_)** 提升大数字可读性:

const num = 1_000_000_000; // 等价于 1000000000

-** Promise 新增方法(Promise.any())** 只要有一个 Promise 成功就返回其结果(与 Promise.all 相反):

Promise.any([fetch('url1'), fetch('url2')]).then(firstSuccess => ...);

###** ES2022(ES13)- 2022 年 - 类字段声明 **- 公有字段:class A { x = 1; }

  • 私有字段(# 前缀,真正私有,外部无法访问):class A { #x = 1; }

-** 顶层 await** 在模块顶层直接使用 await(无需包裹在 async 函数中):

// module.js
const config = await fetch('/config');
export default config;

-Array.prototype.at() 支持负索引访问数组元素(替代 arr[arr.length - 1]):

[1, 2, 3].at(-1); // 3(最后一个元素)

-Object.hasOwn() 判断对象自身是否有某个属性(替代 Object.prototype.hasOwnProperty.call):

Object.hasOwn({ a: 1 }, 'a'); // true

###** ES2023(ES14)- 2023 年 - 数组查找从末尾开始(findLast() / findLastIndex())** 从数组末尾查找元素(避免反转数组):

[1, 2, 3, 2].findLast(x => x === 2); // 2(最后一个匹配项)
[1, 2, 3, 2].findLastIndex(x => x === 2); // 3

-toReversed() / toSorted() / toSpliced() / with() 数组的不可变操作(返回新数组,不修改原数组):

const arr = [3, 1, 2];
arr.toSorted(); // [1, 2, 3](原数组不变)

###** ES2024(ES15)- 2024 年 **-ArrayBuffer.prototype.transfer() 转移 ArrayBuffer 所有权(优化内存性能,避免复制):

const buf = new ArrayBuffer(1024);
const transferred = buf.transfer(); // 原 buf 失效

-Promise.withResolvers() 简化 Promise 控制(无需嵌套函数):

const { promise, resolve, reject } = Promise.withResolvers();
// 可在外部调用 resolve/reject

-** 正则表达式 v 标志 ** 增强 Unicode 匹配(支持属性逃逸和集合运算)。

总结

ES 每年的更新遵循 “小步快跑” 原则,聚焦解决实际开发痛点:

  • 早期(2016-2019)以基础 API 补全为主(如 includes、flat)。
  • 中期(2020-2022)引入革命性语法(?.、??、类私有字段)。
  • 近期(2023-2024)侧重不可变操作和性能优化。

这些特性逐步提升了 JavaScript 的开发效率和安全性,同时保持了语言的向后兼容。