ES2021新特性一览

517 阅读3分钟

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

注意:分隔符只能在数字之间,不可连续。分隔符不影响数值的类型转换值,也无法在字符串转数值时被识别。