ES2021 新增了以下功能:
String.prototype.replaceAll()
Promise.any()
和AggregateError
- 数字分隔符(
_
) - 逻辑赋值运算符
WeakRefs
replaceAll()
替换正则表达式或字符串的所有匹配项。
String.prototype.replaceAll(searchValue, replaceValue)
searchValue
可以是一个字符串或正则表达式。
console.log('x'.replace('', '_')) // '_x'
console.log('xxx'.replace(/(?:)/g, '_')) // '_x_x_x_'
console.log('xxx'.replaceAll('', '_')) // '_x_x_x_'
// 不带 /g 的情况下,将报错
console.log('aaa'.replaceAll(/a/, 'x')) // TypeError: String.prototype.replaceAll called with a non-global RegExp argument
console.log('aaa'.replaceAll(/a/g, 'x')) // 'xxx'
在匹配的子字符串之前、内部和之后插入文本:
console.log('a1 a2'.replaceAll(/a/g, "($`|$&|$')")) // '(|a|1 a2)1 (a1 |a|2)2'
插入位置组的捕获:
const regExp = /^([A-Za-z]+): (.*)$/gu
'first: Jane'.replaceAll(regExp, 'KEY: $1, VALUE: $2') // 'KEY: first, VALUE: Jane'
.*
— 单个字符匹配任意次,即贪婪匹配u
— Unicode 模式g
— 全局匹配,查找所有的匹配项
插入命名组的捕获:
const regExp = /^(?<key>[A-Za-z]+): (?<value>.*)$/gu
'first: Jane'.replaceAll(regExp, 'KEY: $<key>, VALUE: $<value>') // 'KEY: first, VALUE: Jane'
Promise.any()
返回一个 Promise,它的解决方式取决于参数 promises
(它指的是一个可迭代的 Promises)。
- 如果第一个 Promise 完成,则使用 Promise
resolved
const promises = [
Promise.reject('ERROR A'),
Promise.reject('ERROR B'),
Promise.resolve('result')
]
Promise.any(promises).then(console.log) // 'result'
- 如果所有的 Promise 都被拒绝,将返回一个包含所有拒绝值的
AggregateError
实例。
const promises = [
Promise.reject('ERROR A'),
Promise.reject('ERROR B'),
Promise.reject('ERROR C')
]
Promise.any(promises).catch((aggregateError) =>
console.log(aggregateError.errors)
)
// ['ERROR A', 'ERROR B', 'ERROR C']
为了增加更大数字的可读性,从 ES2021 开始,我们可以在数字中使用下划线(_
)作为分隔符。
数字组之间的视觉分离:
console.log(1_234_456_789.01) // 1234456789.01
console.log(1_000_000_000) // 1000000000
const fileSystemPermission = 0b111_111_000 // 504
const bytes = 0b1111_10101011_11110000_00001101 // 262926349
const words = 0xa0_b0_c0 // 10531008
我们还可以在分数和指数中使用分隔符:
0.000_001 // 0.000001
1e10_000 // Infinity
const massOfElectronInKg = 9.109_383_56e-31 // 9.10938356e-31
const trillionInShortScale = 1e1_2 // 1000000000000
分隔符的位置有两种限制:
- 我们只能在两位数之间加下划线。因此,以下所有数字都是非法的:
3_.141
3._141
1_e12
1e_12
_1464301
1464301_
0_b111111000
0b_111111000
- 我们不能连续使用多个下划线:
123__456 // 不允许
这些限制背后的动机是保持解析简单并避免奇怪的边缘情况。
以下解析数字的函数不支持分隔符:
Number()
parseInt()
parseFloat()
console.log(Number('123_456')) // NaN
console.log(parseInt('123_456')) // 123
console.log(parseFloat('123_456.123')) // 123
理由是数字分隔符用于代码。其他类型的输入应该以不同的方式处理。
Bigint
通常用于代表金融技术领域的货币。我们可以在 bigint
类型中使用下划线(_
)作为分隔符:
const massOfEarthInKg = 1_000_00n // 100000n
与数字一样,有两个限制:
- 我们只能在两位数之间加一个下划线。
- 我们最多可以连续使用一个下划线。
||=
、&&=
和 ??=
,它们都是二元运算符,增加了赋值功能。
| 赋值运算符 | 相当于 | 仅当 a 是 |
| ---------- | -------------- | --------- | --- | --- | -------- | ------- |
| a | | = b
| a | | (a = b)
| false
|
| a &&= b
| a && (a = b)
| true
|
| a ??= b
| a ?? (a = b)
| null
|
对于 ||=
,如果左侧为 false
,则评估右侧表达式并将其分配给左侧变量。
let x = 0
let y = 1
console.log((x ||= y)) // 1
console.log(x || (x = y)) // 1
const updateID = (user) => {
if (!user.id) user.id = 1
// Or
user.id = user.id || 1
// 使用逻辑或赋值运算符
user.id ||= 1
}
对于 &&=
,如果左侧为 true
,则评估右侧表达式并将其分配给左侧的变量。
let x = 1
let y = 2
console.log((x &&= y)) // 2
console.log(x && (x = y)) // 2
对于 ??=
,如果左侧值为 null
或 undefined
,则评估右侧表达式并将其分配给左侧的变量。
console.log((x ??= y))
console.log(x ?? (x = y))
function setOpts(opts) {
opts.cat ??= 'meow'
opts.dog ??= 'bow'
return opts
}
setOpts({ cat: 'meow' }) // {cat: 'meow', dog: 'bow'}
WeakRef
是一个帮助您创建对象的弱引用的类,因此它们可以被垃圾收集。而 FinalizationRegistry
对象可以让你在对象被垃圾回收时请求一个回调。
let target = {}
let wr = new WeakRef(target)
// wr 和 target 是不一样的
// 创建新注册表
const registry = new FinalizationRegistry((heldValue) => {
// ...
})
registry.register(myObject, 'some value', myObject)
// ...过了一段时间,如果你不再关心 myObject
registry.unregister(myObject)