即将发布的 ES2021 中有哪些有趣的功能

开发 前端
在本文中,你将将会了解五个最有趣的功能:String.prototype.replaceAll(),数字分隔符,逻辑赋值运算符,Promise.any(),WeakRef 和Finalizers。

本文转载自微信公众号“前端先锋”(jingchengyideng)。

简述

ES2021(ES12)将于 2021 年中发布。在本文中,你将将会了解五个最有趣的功能:String.prototype.replaceAll(),数字分隔符,逻辑赋值运算符,Promise.any(),WeakRef 和Finalizers。

本文所描述的五个功能目前都处于第 4 阶段。这意味着它们已经完成,并将要在 JavaScript 引擎中实现了。这意味着你不会浪费时间去学习一些可能永远也不会出现的东西。

这些功能不久将会发布。如果有兴趣,可以到官方 Ecma TC39 GitHub (https://github.com/tc39/proposals) 去了解有关其他提案的更多信息。这个 Github 库跟踪了所有提案以及其当前所处的阶段。

String.prototype.replaceAll()

先从一个小功能 replaceAll() 开始,这是对 JavaScript 语言的一个补充。当你要替换字符串中多次出现的匹配模式时,目前可以用 replace() 方法,但问题是它只能替换第一次出现的那个。

这并不意味着 replace() 不能替换所有出现的匹配模式,只不过你必须用正则表达式才行。如果你可以接受那就没事儿了。不过对于很多 js 程序员来说,正则表达式并不是他们的菜(实际上是懒得学!)。

如果你就是这样的 js 程序员,肯定喜欢新的 replaceAll() 方法。它的工作方式与 replace() 类似,区别在于 replaceAll() 可以不用正则表达式就能替换所有出现的模式。

replaceAll() 也能接受正则表达式,你完全可以用它代替 replace() 。

// 声明一个字符串 
let str = 'There are those who like cats, there those who like watching cats and there are those who have cats.' 
 
// 用 dogs 替换所有的“cats”: 
strstr = str.replaceAll('cats', 'dogs') 
console.log(str) 
// Output: 
// 'There are those who like dogs, there those who like watching dogs and there are those who have dogs.' 
 
// 用 replace() 的写法: 
strstr = str.replace(/cats/g, 'dogs') 
console.log(str) 
// Output: 
// 'There are those who like dogs, there those who like watching dogs and there are those have dogs.' 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

数字分隔符

这是 JavaScript ES2021的一个非常小的功能,可以让你在处理大量数字时更好过一点。数字分隔符提供了一种能使大数字更易于阅读和使用的简单方法。语法也很简单:一个下划线 _。

// 不带数字分隔符的 Number  
const num = 3685134689 
 
// 带数字分隔符的 Number  
const num = 3_685_134_689 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

不过数字分隔符只是在视觉上提供一些帮助。在使用时不会对数值本身产生任何影响。

// 带数字分隔符的 Number  
const num = 3_685_134_689 
 
// 输出: 
console.log(num) 
// Output: 
// 3685134689 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

逻辑赋值运算符

JavaScript 允许在布尔上下文中使用逻辑运算符。例如在 if ... else语句和三目运算符中检测是 true 还是 false。ES2021 的逻辑赋值运算符将逻辑运算符与赋值表达式(=)组合在了一起。

在 JavaScript 中已经有了一些赋值运算符,例如:加法赋值(+=),减法赋值(-=),乘法赋值(*=)等。在 ES2021 中又增加了对逻辑运算符 &&,|| 和 ??([空值合并)的支持。

////////////////// 
// 逻辑与赋值运算符 (&&=) 
////////////////// 
x &&= y 
 
// 以上代码相当于: 
xx = x && d 
// 或者: 
if (x) { 
  x = y 

 
// 例1: 
let x = 3  
let y = 0  
x &&= y 
console.log(x) 
// Output: 
// 0 
 
// 例 2: 
let x = 0  
let y = 9  
x &&= y 
console.log(x) 
// Output: 
// 0 
 
// 例 3: 
let x = 3 // Truthy value. 
let y = 15 // Truthy value. 
x &&= y 
console.log(x) 
// Output: 
// 15 
 
 
////////////////// 
// 逻辑或赋值运算符 (||=): 
x ||= y 
 
// 相当于: 
xx = x || y 
// 或者: 
if (!x) { 
  x = y 

 
// 例 1: 
let x = 3 
let y = 0 
x ||= y 
 
console.log(x) 
// Output: 
// 3 
 
// 例 2: 
let x = 0  
let y = 9  
x ||= y 
 
console.log(x) 
// Output: 
// 9 
 
// 例 3: 
let x = 3  
let y = 15 
x ||= y 
 
console.log(x) 
// Output: 
// 3 
 
 
///////////////////////// 
// 空值合并赋值运算符 (??=): 
///////////////////////// 
x ??= y 
 
// 相当于: 
xx = x ?? y 
// 或者: 
if (x == null || x == undefined) { 
    x = y 

 
// 例 1: 
let x = null  
let y = 'Hello'  
x ??= y 
console.log(x) 
// Output: 
// 'Hello' 
 
// 例 2: 
let x = 'Jay'  
let y = 'Hello'  
x ??= y 
console.log(x) 
// Output: 
// 'Jay' 
 
// 例 3: 
let x = 'Jay' 
let y = null  
x ??= y 
console.log(x) 
// Output: 
// 'Jay' 
 
// 例 4: 
let x = undefined  
let y = 'Jock'  
x ??= y 
 
console.log(x) 
// Output: 
// 'Jock' 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.

看一下上面的例子。首先是 x && = y。仅当 x 为真时,才将 y 赋值给 x。其次是 x || = y,仅当 x 为假时,才将 y 赋值给 x。如果 x 是真,而 y 是假,则不会进行赋值。

如果 x 和 y 都是假,也会发生同样的情况。最后是 x ?? = y。仅当 x 为 null 或 undefined 时,才将 y 分配给 x。如果 x 既不是 null 也不是 undefined 则不会进行赋值,如果 y 为 null 或 undefined 也一样。

Promise.any()

在 ES6 中引入了 Promise.race() 和 Promise.all() 方法,ES2020 加入了 Promise.allSettled()。ES2021 又增加了一个使 Promise 处理更加容易的方法:Promise.any() 。

Promise.any() 方法接受多个 promise,并在完成其中任何一个的情况下返回 promise。其返回的是 Promise.any() 完成的第一个 promise。如果所有 promise 均被拒绝,则 Promise.any() 将返回 AggregateError,其中包含拒绝的原因。

// 例 1: 全部被完成: 
// 创建 promises: 
const promise1 = new Promise((resolve, reject) => { 
  setTimeout(() => { 
    resolve('promise1 is resolved.') 
  }, Math.floor(Math.random() * 1000)) 
}) 
 
const promise2 = new Promise((resolve, reject) => { 
  setTimeout(() => { 
    resolve('promise2 is resolved.') 
  }, Math.floor(Math.random() * 1000)) 
}) 
 
const promise3 = new Promise((resolve, reject) => { 
  setTimeout(() => { 
    resolve('promise3 is resolved.') 
  }, Math.floor(Math.random() * 1000)) 
}) 
 
;(async function() { 
  // Await the result of Promise.any(): 
  const result = await Promise.any([promise1, promise2, promise3]) 
  console.log(result) 
  // Output: 
  // 'promise1 is resolved.', 'promise2 is resolved.' or 'promise3 is resolved.' 
})() 
 
 
// 例 2: 部分完成: 
const promise1 = new Promise((resolve, reject) => { 
  setTimeout(() => { 
    resolve('promise1 is resolved.') 
  }, Math.floor(Math.random() * 1000)) 
}) 
 
const promise2 = new Promise((resolve, reject) => { 
  setTimeout(() => { 
    reject('promise2 was rejected.') 
  }, Math.floor(Math.random() * 1000)) 
}) 
 
;(async function() { 
  // Await the result of Promise.any(): 
  const result = await Promise.any([promise1, promise2]) 
  console.log(result) 
  // Output: 
  // 'promise1 is resolved.' 
})() 
 
 
// 例 3: 均被拒绝: 
const promise1 = new Promise((resolve, reject) => { 
  setTimeout(() => { 
    reject('promise1 was rejected.') 
  }, Math.floor(Math.random() * 1000)) 
}) 
 
const promise2 = new Promise((resolve, reject) => { 
  setTimeout(() => { 
    reject('promise2 was rejected.') 
  }, Math.floor(Math.random() * 1000)) 
}) 
 
;(async function() { 
  // Use try...catch to catch the AggregateError: 
  try { 
    // Await the result of Promise.any(): 
    const result = await Promise.any([promise1, promise2]) 
  } 
 
  catch (err) { 
    console.log(err.errors) 
    // Output: 
    // [ 'promise1 was rejected.', 'promise2 was rejected.' ] 
  } 
})() 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.

弱引用:WeakRef

最后一个抢眼的功能是 WeakRefs。在 JavaScript 中,当你创建了一个创建对象的引用时,这个引用可以防止对象被 gc 回收,也就是说 JavaScript 无法删除对象并释放其内存。只要对该对象的引用一直存在,就可以使这个对象永远存在。

ES2021 了新的类 WeakRefs。允许创建对象的弱引用。这样就能够在跟踪现有对象时不会阻止对其进行垃圾回收。对于缓存和对象映射非常有用。

必须用 new关键字创建新的 WeakRef ,并把某些对象作为参数放入括号中。当你想读取引用(被引用的对象)时,可以通过在弱引用上调用 deref() 来实现。下面是一个非常简单的例子。

const myWeakRef = new WeakRef({ 
  name: 'Cache', 
  size: 'unlimited' 
}) 
 
console.log(myWeakRef.deref()) 
// Output: 
// { name: 'Cache', size: 'unlimited' } 
 
console.log(myWeakRef.deref().name) 
// Output: 
// 'Cache' 
 
console.log(myWeakRef.deref().size) 
// Output: 
// 'unlimited' 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

Finalizers 和 FinalizationRegistry

与 WeakRef 紧密相连的还有另一个功能,名为 finalizers 或 FinalizationRegistry。这个功能允许你注册一个回调函数,这个回调函数将会在对象被 gc 回收时调用。

// 创建 FinalizationRegistry: 
const reg = new FinalizationRegistry((val) => { 
  console.log(val) 
}) 
 
;(() => { 
  // 创建新对象: 
  const obj = {} 
 
  //为 “obj” 对象注册 finalizer: 
  //第一个参数:要为其注册 finalizer 的对象。 
  //第二个参数:上面定义的回调函数的值。 
  reg.register(obj, 'obj has been garbage-collected.') 
})() 
// 当 "obj" 被gc回收时输出: 
// 'obj has been garbage-collected.' 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

官方建议不要轻易使用 WeakRef 和 finalizer。其中一个原因是它们可能不可预测,另一个是它们并没有真正帮 gc 完成工作,实际上可能会gc的工作更加困难。你可以在它的提案(https://github.com/tc39/proposal-weakrefs#a-note-of-caution)中详细了解其原因。

总结

与以前的 JavaScript 规范(例如 ES6 和 ES2020)相比,看上去 ES2021的更新不多,但是这些有趣的功能值得我们关注。

 

责任编辑:赵宁宁 来源: 前端先锋
相关推荐

2023-11-24 08:31:03

ECMAScriptES2021

2021-09-04 05:00:26

ESES2021ES12

2009-10-23 14:22:59

Windows 7微软隐藏功能

2020-07-29 10:00:38

PythonEllipsis索引

2023-05-22 16:03:00

Javascript开发前端

2020-10-14 13:12:19

Windows 10操作系统微软

2020-07-26 12:01:08

PythonPython 3.8开发

2018-03-05 11:10:10

Android P工程师谷歌

2018-03-04 08:37:17

谷歌Android开发者

2022-04-02 10:31:32

ThunderbirLinux

2023-08-13 16:32:12

JavaScript

2020-11-23 11:34:52

ES6

2024-10-18 14:52:16

2011-01-26 11:38:37

BlackBerry

2016-11-22 14:12:13

2025-03-19 09:55:17

2021-03-03 12:33:31

微软Windows SerInsider

2022-07-07 15:50:19

Python开发功能

2024-04-29 13:54:12

iOS 18苹果

2017-09-06 15:14:25

苹果发布iOS 11
点赞
收藏

51CTO技术栈公众号