新特性
从 ECMAScript 2015 开始,TC39 委员会改为每年发布一版新 ECMAScript 规范。这样各个提案可以 独立发展,每年所有达到成熟阶段的提案会被打包发布到新一版标准中。不过,打包多少特性并不重要,主要取决于浏览器厂商实现的情况。一旦提案进入第 4 阶段(stage 4),其内容就不会更改,并通常会包 含在下一版 ECMAScript 规范中,浏览器就会着手根据自己的计划实现提案的特性。
ECAMScript 7
ECMAScript 7(也称为 ES2016)是 JavaScript 标准的第七版,于 2016 年发布。ES7 引入了一些新特性和改进,旨在提高 JavaScript 的功能和开发效率。
Array.prototype.includes
Array.prototype.includes
方法用于判断数组中是否包含某个元素,并返回布尔值。它解决了 Array.prototype.indexOf
方法在判断数组是否包含 NaN 时的一些问题。
const array = [1, 2, 3, NaN];
console.log(array.includes(2)); // true
console.log(array.includes(NaN)); // true
指数运算符
ES7 引入了指数运算符 **
,用来进行幂运算。
// 计算 (2 的 3 次方)
console.log(2 ** 3); // 8
这些是 ES7 引入的主要新特性和改进。虽然 ES7 相对于之前的版本变化较小,但这些特性都对 JavaScript 编程有着重要的影响和帮助,特别是在处理数组、异步操作和多线程编程方面提供了更多的选择和便利。
ECAMScript 8
ECMAScript 8(也称为 ES2017)是 JavaScript 标准的第七版,于 2017 年发布。ES8 引入了一些新特性和改进,旨在提高 JavaScript 的功能和开发效率。
Async 函数
Async 函数(异步函数)是一个语法糖,简化了使用 Promise 处理异步操作的代码。它可以让异步代码看起来像同步代码,使得异步操作更加容易理解和维护。
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}
fetchData().then(data => {
console.log(data);
});
SharedArrayBuffer 和 Atomics 对象
SharedArrayBuffer
和 Atomics
对象是为了支持多线程编程而引入的。SharedArrayBuffer
允许多个线程共享同一块内存,而 Atomics
对象则提供了一组静态方法来操作 SharedArrayBuffer
中的原子操作。
// 示例代码需要在支持 SharedArrayBuffer 的环境中运行
const buffer = new SharedArrayBuffer(16);
const intArray = new Int32Array(buffer);
Atomics.store(intArray, 0, 42); // 将值 42 存储在第一个位置
函数变化
允许在函数参数列表和调用中的尾随逗号。
function foo(a, b, c,) {
// ...
}
foo(1, 2, 3,);
新增 API
返回一个给定对象自身可枚举属性值的数组。
返回一个给定对象自身可枚举属性的键值对数组。
Object.getOwnPropertyDescriptors()
返回一个对象自身属性的描述符的对象。
Object.padStart() 和 Object.padEnd()
添加了两个新方法用于字符串填充:padStart()
和 padEnd()
。
ECAMScript 9
ECMAScript 2018 (ES9) 引入了几项新功能和改进。以下是 ES9 的主要更新内容:
异步迭代
ES9 引入了异步迭代器和 for-await-of
循环。这使得在循环中处理异步操作更加容易,方便处理异步数据源。
async function processData(stream) {
for await (const chunk of stream) {
console.log(chunk);
}
}
剩余属性和展开属性
ES9 为对象解构赋值添加了剩余属性,并为对象字面量添加了展开属性。
const { a, b, ...rest } = { a: 1, b: 2, c: 3, d: 4 };
console.log(rest); // { c: 3, d: 4 }
const obj1 = { x: 1, y: 2 };
const obj2 = { ...obj1, z: 3 };
console.log(obj2); // { x: 1, y: 2, z: 3 }
正则表达式改进
命名捕获组:使用命名捕获组可以更清晰地捕获匹配的子字符串。
const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const result = re.exec('2023-06-27');
console.log(result.groups.year); // 2023
正则表达式反向断言:支持正向断言和反向断言。
const re = /(?<=\$)\d+/;
const result = re.exec('$123');
console.log(result[0]); // 123
Promise.finally
ES9 为 Promise 对象添加了 finally
方法,无论 Promise 是成功还是失败,finally
方法都会执行。
fetch('https://api.example.com/data')
.then(response => response.json())
.catch(error => console.error(error)) // TypeError: Failed to fetch
.finally(() => console.log('请求完成')); // 请求完成
模板字符串改进
允许在模板字符串中使用转义序列。
const str = `行尾的换行符会被移除:\u2028这是一个新行`;
console.log(str);
\u2028
和 \u2029
在 Unicode 中分别表示行分隔符(Line Separator)和段落分隔符(Paragraph Separator) 。它们在某些文本处理应用程序中有特定的意义,例如文本编辑器和一些文档处理系统会将它们解释为换行符或段落分隔符。然而,在大多数编程语言和环境中,包括 JavaScript 和 Node.js,这些字符通常被视为普通的 Unicode 字符,而不会自动导致换行。
为了在模板字符串中实现换行,你可以使用实际的换行符 \n
或使用多行字符串的方式:
const str = `这是第一行\n这是第二行`;
console.log(str);
ECAMScript 10
ES10(ECMAScript 2019)引入了一些新特性和改进。以下是ES10的主要新特性:
Function.prototype.toString 改进
现在返回函数的精确字符,包括空格和注释。
function person() {
// 函数逻辑
}
console.log(person.toString());
/** 输出
function person() {
// 函数逻辑
}
*/
try...catch 中的可选 catch 绑定
现在可以在 catch 语句中省略对错误对象的绑定。
try {
// code
} catch {
// handle error
}
新增 API
Array.prototype.flat
用于将嵌套的数组“拉平”,即将多层嵌套的数组转换为一维数组。
Array.prototype.flatMap
首先对数组中的每个元素进行映射处理,然后将结果压缩成一个新数组。
String.prototype.trimStart
移除字符串开头的空白字符。
String.prototype.trimEnd
移除字符串结尾的空白字符。
将一个键值对数组转换为对象。
Symbol.prototype.description
这个属性允许直接获取 Symbol 的描述。
ECAMScript 11
ES11(或称为 ECMAScript 2020)是 JavaScript 的一个重要版本,它引入了一些新的语言特性和改进。以下是 ES2020 中一些主要的特性:
可选链操作符
允许在访问深层对象属性或方法时,如果中间某个属性或方法不存在或为 null
或 undefined
,则不会抛出错误,而是返回 undefined
。
const user = {};
const city = user?.address?.city; // undefined
空值合并运算符
用于检查某个值是否为 null
或 undefined
,如果是,则返回默认值,否则返回该值本身。
let flag; // 分配了 undefined
console.log(flag ?? '默认值');
let falg2 = true;
console.log(falg2 ?? '默认值'); // 返回该值本身: true
BigInt 数据类型
引入了一种新的原始数据类型 BigInt
,用于表示任意精度的整数值,可以用 n
后缀来标识。
const bigNumber = 123456789012345678901234567890n;
动态导入
引入了 import()
函数,允许在运行时动态地导入模块,而不必在静态代码中预先声明依赖关系。
const module = await import('./path/to/module.js');
全局对象 globalThis
提供了一个标准的方式来获取全局对象,不论在不同的环境(浏览器、Node.js 等)中运行,都可以使用 globalThis。
console.log(globalThis); // Windows
console.log(globalThis); // Windows
/*
<ref *1> Object [global] {
global: [Circular *1],
queueMicrotask: [Function: queueMicrotask],
clearImmediate: [Function: clearImmediate],
setImmediate: [Function: setImmediate] {
[Symbol(nodejs.util.promisify.custom)]: [Getter]
},
structuredClone: [Getter/Setter],
clearInterval: [Function: clearInterval],
clearTimeout: [Function: clearTimeout],
setInterval: [Function: setInterval],
setTimeout: [Function: setTimeout] {
[Symbol(nodejs.util.promisify.custom)]: [Getter]
},
atob: [Getter/Setter],
btoa: [Getter/Setter],
performance: [Getter/Setter],
fetch: [AsyncFunction: fetch]
}
*/
ECAMScript 12
ECMAScript 2021(也称为 ES12)是 JavaScript 的一个重要版本,引入了一些新的语言特性和改进。以下是 ECMAScript 2021 的主要内容:
新增逻辑赋值运算符
逻辑或赋值运算符 ||=
该运算符会在左侧操作数为 falsy 值(false、0、''、null、undefined、NaN)时进行赋值操作。
x ||= y;
// 等价于
x || (x = y);
let a = 0;
a ||= 1;
console.log(a); // 输出: 1,因为 0 是 falsy 值
let b = 2;
b ||= 1;
console.log(b); // 输出: 2,因为 2 是 truthy 值
逻辑与赋值运算符 &&=
该运算符会在左侧操作数为 truthy 值时进行赋值操作。
x &&= y;
// 等价于
x && (x = y);
let a = 2;
a &&= 3;
console.log(a); // 输出: 3,因为 2 是 truthy 值
let b = 0;
b &&= 3;
console.log(b); // 输出: 0,因为 0 是 falsy 值
逻辑空赋值运算符 ??=
该运算符会在左侧操作数为 null
或 undefined
时进行赋值操作。
x ??= y;
// 等价于
x ?? (x = y);
let a = null;
a ??= 1;
console.log(a); // 输出: 1,因为 a 是 null
let b = undefined;
b ??= 2;
console.log(b); // 输出: 2,因为 b 是 undefined
let c = 0;
c ??= 3;
console.log(c); // 输出: 0,因为 0 不是 null 或 undefined
let d = false;
d ??= 4;
console.log(d); // 输出: false,因为 false 不是 null 或 undefined
数字分隔符
数字分隔符允许在数字字面量中使用下划线 _
进行分隔,提高可读性。
const largeNumber = 1_000_000_000;
const creditCardNumber = 1234_5678_9012_3456;
WeakRef 和 FinalizationRegistry
WeakRef
:允许创建对对象的弱引用,这样不会阻止对象被垃圾回收。
let obj = { name: 'John' };
let weakRef = new WeakRef(obj);
obj = null; // `obj` 现在可以被垃圾回收
FinalizationRegistry
:允许注册回调函数,在对象被垃圾回收时执行清理操 作。
const registry = new FinalizationRegistry(heldValue => {
console.log(`Cleaning up ${heldValue}`);
});
let obj = { name: 'John' };
registry.register(obj, 'some resource');
obj = null; // 当 `obj` 被垃圾回收时,回调函数会被调用
Promise.any
Promise.any
方法接受一个 Promise 数组,并返回最先解决(fulfilled)的 Promise 的值。如果所有 Promise 都拒绝(rejected),则返回一个 AggregateError。
const promises = [
Promise.reject(new Error('Error 1')),
Promise.resolve('Success 1'),
Promise.reject(new Error('Error 2')),
];
Promise.any(promises)
.then(result => {
console.log(result); // 输出:Success 1
})
.catch(error => {
console.error(error); // 捕获 AggregateError
});
私有字段和方法
ES2021 进一步增强了类的私有性支持,引入了私有字段和私有方法。私有字段和方法以 # 作为前缀,只能在类内部访问。
class MyClass {
#privateField = 42;
#privateMethod() {
console.log(this.#privateField);
}
publicMethod() {
this.#privateMethod();
}
}
const instance = new MyClass();
instance.publicMethod(); // 输出:42
// instance.#privateMethod(); // 会抛出 SyntaxError
新增 API
Object.hasOwn()
hasOwn
是一个新的静态方法,用于检查对象自身是否具有某个属性。
String.prototype.replaceAll()
replaceAll
方法用于替换字符串中所有匹配的子串。
ECAMScript 13
ECMAScript 2022(也称为 ES13)是 JavaScript 的一个重要版本,引入了一些新的语言特性和改进。以下是 ECMAScript 2022 的主要内容:
顶层 await
允许顶层使用 await
,而无需将其放在 async
函数内,需要在 ES 模块中使用,保存为 .mjs
文件或修改 package.json
为模块。这简化了异步代码的编写。
{
"type": "module"
}
// 顶层 await 示例
const response = await fetch(
'https://v1.hitokoto.cn/?c=d&c=i&encode=json&lang=cn',
);
const data = await response.json();
console.log(data); // 随机诗句
正则表达式匹配索引
正则表达式匹配索引功能允许你在使用正则表达式匹配字符串时获取匹配结果的索引。通过使用 .matchAll
方法,你可以获得每个匹配项的详细索引信息。
const regex = /t(e)(st(\d?))/g;
const str = 'test1test2';
const matches = [...str.matchAll(regex)];
console.log(matches[0].indices); // 输出 [[0, 5], [1, 2], [3, 5], [4, 5]]
新增 API
Array.prototype.at()
Array.prototype.at
方法允许你使用正负整数来访问数组的元素。负整数从数组末尾开始计数,使得访问最后一个元素变得更加方便。
ECAMScript 14
ECMAScript 2023(ECMAScript 14 或 ES14)它引入了若干新特性和改进,进一步增强了语言的功能和开发者体验。以下是 ECMAScript 2023 的一些主要更新内容及其详细描述:
哈希带单位的 Symbol
允许在创建 Symbol
时添加描述性标签,这有助于在调试和日志记录时更好地理解和区分 Symbol
。
const sym1 = Symbol('description1');
const sym2 = Symbol('description2');
console.log(sym1.description); // 输出 'description1'
console.log(sym2.description); // 输出 'description2'
函数参数解构默认值
在函数参数解构时,支持设置默认值。
function example({ a = 1, b = 2 } = {}) {
console.log(a, b);
}
example(); // 输出 1 2
example({ a: 3 }); // 输出 3 2
正则表达式装饰器
正则表达式装饰器是一种新的语法,允许你在正则表达式中使用更加灵活和可读的模式。