2021 Ecma 国际大会推出了 ES12 版本。相比 ES11 今年的新特性不多,这也预示着语言环境趋于稳定。官网指引
String.prototype.replaceAll()
replaceAll 会按目标全局匹配原字符串,返回替换为特定值的副本(不修改字符串)。
// new
'tom amy tom'.replaceAll('tom', 'tony')
// "tony amy tony"
// old
'tom amy tom'.replace(/tom/g, 'tony')
// "tony amy tony"
- 用途:无需传入正则表达式即可全局替换字符串。
- 注意:replaceAll 和 replace 的传参返回值类型一致,但是 replaceAll 要求正则表达式参数修饰符为 g
// 全局匹配
'tom amy tom'.replace(/tom/m, 'tony')
// "tony amy tony"
// 大小写不敏感
'tom amy tom'.replaceAll(/tom/i, 'tony')
// TypeError: String.prototype.replaceAll called with a non-global RegExp argument
// 多行匹配
'tom amy tom'.replace(/tom/m, 'tony')
// TypeError: String.prototype.replaceAll called with a non-global RegExp argument
replaceAll 没有带来新的功能,简化了全局替换的调用方式。
Promise.any
any 接受 Promise 数组作为参数,返回合成的 Promise。当其中第一个 Promise 成功,整体返回成功;当全部失败,整体失败返回 AggregateError(Error 的子类,目前处于提案第三阶段)。
const promises = [
fetch('/endpoint-a').then(() => 'a'),
fetch('/endpoint-b').then(() => 'b'),
fetch('/endpoint-c').then(() => 'c'),
];
try {
const first = await Promise.any(promises);
console.log(first);
} catch (error) {
console.log(error); // AggregateError
}
注意:异常情况下返回的 AggregateError 是多条异常的汇总。实例的 errors 属性可用于遍历异常。
const list = [
new Error("first error"),
new Error("second error"),
];
const e = new AggregateError(list, 'xxx');
Array.isArray(e.errors)
// true
list === e.errors
// false
list[0] === e.errors[0]
// true
Promise 多转一方法汇总
名称 | 描述 |
---|---|
all | 只要一个 Promise 失败,立即返回失败,全成功返回成功数组 |
any | 只要一个 Promise 成功,立即返回成功,全失败返回 AggregateError |
allSettled | 所有 Promise 完成才返回(无论成功失败),返回结果数组 |
race | 只要一个 Promise 完成就返回结果(无论成功失败) |
WeakRefs
WeakRefs 用于构造对象的弱引用,其 deref 方法返回引用,在对象被 JS 引擎垃圾回收清除后返回 undefined。
const obj = {};
const wr = new WeakRef(obj);
// 很久很久以后
wr.deref() // obj|undefined
注意:尽量避免使用。不应依赖任何规范没有保证的行为,垃圾回收的行为在不同引擎或同一引擎的不同版本都可能差异很大。 同一对象构造的 WeakRef 的 deref 方法,在同一时间返回相同结果。
FinalizationRegistry
FinalizationRegistry 用于构造监听对象被垃圾回收器清除的回调。
const registry = new FinalizationRegistry(heldValue => {
console.log('----', heldValue);
});
const obj = {};
const token = {};
// 注册监听
registry.register(obj, "some value", token);
// 取消监听
registry.unregister(token);
// 或者,很久以后,回调执行
// ---- some value
register:参数依次为监听的引用、回调的传参、取消的标识,其中不提供取消的标识将无法取消监听。
注意:清理对象的回调中不应包含必要的逻辑,回调可能始终不会执行,引擎可能在运行过程中都没清理该对象。
对于对象引用的回收,WeakRefs 用于关注状态,FinalizationRegistry 用于即时反应。
逻辑赋值运算符
??=
??= 的判断逻辑和 ?? 一致,左值为 null 或 undefined 时返回右值,否则返回左值。不同的是 ??= 包含向左值赋值的操作。
// new
let a = null;
a ??= {}; // {}
// old
let a = null;
a = a ?? {}; // {}
&&= 和 ||=
&&= 和 ||= 作为 && 和 || 的赋值运算符,判断逻辑以转换为布尔值的值为准。
// new
let a = false;
a &&= true; //false
a ||= true; //true
// old
let a = false;
a = a && true; // false
a = a || true; // true
简化了 ?? && || 运算符在赋值目标与逻辑判断左值相同的语法。
_数字分隔符
允许数值字面量中间包含不连续_,以提高可读性。
let y = 1_1; // 11
y = 1_; // SyntaxError: Numeric separators are not allowed at the end of numeric literals
y = _1; // ReferenceError: _1 is not defined
y = 1__1; // SyntaxError: Only one underscore is allowed as numeric separator
y = Number('1_1'); // NaN
注意:分隔符只能在数字之间,不可连续。分隔符不影响数值的类型转换值,也无法在字符串转数值时被识别。