ECMAScript 2021的亮点包括replaceAll()、promise.any()、AggregateError和新的逻辑赋值运算符,作为开始。让我们深入了解一下。
JavaScript语言规范,也被称为ECMAScript或ES,是一个活的文件,每年都会根据不断变化的需求进行修改。 虽然JavaScript开始是一种脚本语言,但ECMAScript规范概述指出,该语言 "现在被用于许多不同环境和规模的全部编程任务"。正因为如此,JavaScript被更好地理解为一种全功能的通用编程语言。
即将发布的ECMAScript 2022版本就在眼前,让我们来看看ECMAScript 2021中引入的新的JavaScript语言特性。
String.prototype.replaceAll
replaceAll() 方法需要一个字符串或正则表达式,称为模式,作为其第一个参数。第二个参数是模式的替换。给定第一个和第二个参数,replaceAll() ,返回一个新的字符串,该字符串将是源字符串,模式的所有实例都被替换。源字符串不受影响。
在ECMAScript 2021中,replaceAll() 与ECMAScript 2020的matchAll() 一起改进了JavaScript内置的String 对象的固有功能。
replaceAll() 方法的工作原理与replace() 一样,但适用于字符串中的所有出现,而不仅仅是第一个出现。在多年来不得不使用一个库或手工编码的解决方案之后,这是一个受欢迎的补充。
清单1显示了一个简单的例子,其中我们修改了一些莎士比亚。
清单1.replaceAll()
let quote = "all the world's a stage, and all the men and women merely players";
let newQuote = quote.replaceAll("all", "most of");
console.log(newQuote);
promise.any()
promise.any() 方法接收一个承诺的集合,并允许你通过返回一个新的承诺来响应第一个成功完成的承诺。
如果有任何承诺被拒绝,它们将被忽略。(注意这个方法与promise.all() 的对比,后者因任何错误或拒绝而停止;与promise.allSettled() 的对比,后者让你观察一个集合中解决的所有承诺,即使中间有错误。)
如果任何承诺出错,promise.any() 仍然会对集合中第一个解决的承诺采取行动。
如果传入的承诺没有一个解决,promise.any() 方法会返回一个拒绝的承诺。它返回的错误是AggregateError ,这是由ECMAScript 2021引入的新的错误类型。AggregateError 代表所有遇到的错误的摘要。
你可以使用promise.any() ,将许多承诺卷成一个单一的承诺。这个承诺将解决集合中最先解决的问题,忽略了错误和拒绝。 清单2有一个简单的例子。
清单2.promise.any()--全部解决
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, "1 second");
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, "2 second");
});
let promises = [promise1, promise2];
Promise.any(promises).then((firstResolved) => {
console.log(firstResolved); // outputs “1 second”
})
现在考虑清单3,其中所有的承诺最终都因拒绝而失败。
清单3.promise.any()--所有被拒绝的承诺
const promise1 = new Promise((resolve, reject) => {
setTimeout(reject, 1000, "1 second");
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 2000, "2 second");
});
let promises = [promise1, promise2];
Promise.any(promises).then((firstResolved) => {
console.log(firstResolved);
}).catch((err) => { console.log("error: " + err) }) // outputs error: AggregateError: All promises were rejected
在清单3中,我们添加了一个catch处理程序,它在两个承诺都被拒绝后启动。注意,AggregateError 是一个持有关于失败承诺的信息的对象。
让我们仔细看看AggregateError ,它是ECMAScript 2021的另一个新特性。
AggregateError
AggregateError 是一种特殊的错误子类,它将许多错误合并为一个摘要对象。 正如你所看到的,清单3中的 方法创建了一个 。promise.any() AggregateError
在那个例子中,所有传递给promise.any() 的承诺都失败了,所以该方法返回了一个AggregateError 。该错误包含了一个描述错误的消息和一个包含每个错误细节的数组。清单4显示了返回的错误的内容。
清单4.AggregateError
AggregateError: All promises were rejected
errors: Array(2)
0: "1 second"
1: "2 second"
length: 2
message: "All promises were rejected"
stack: "AggregateError: All promises were rejected"
如图所示,AggregateError ,你可以通过AggregateError.errors ,访问导致错误的承诺信息。
新的逻辑赋值运算符
JavaScript有熟悉的数学赋值运算符,如+= ,它一次性完成运算和赋值,是一种便利。ECMAScript 2021增加了对逻辑运算符的类似支持||,??, 和&& 。
让我们来看看其中的每一个。
空值赋值(??=)
你可以使用nullish赋值运算符来测试一个变量是否为空或未定义。如果该变量是空的或未定义的,你可以将表达式的右侧赋值给该变量。清单5是一个例子。
清单5.运行中的?=赋值
let quote = "When goodness is lost there is morality.";
let existingQuote = "A leader is best when people barely know he exists";
let nonExistingQuote = null;
existingQuote ??= quote;
nonExistingQuote ??= quote;
console.log(existingQuote); // A leader is best when people barely know he exists
console.log(nonExistingQuote); // When goodness is lost there is morality.
请注意,当在一个存在的变量上使用时,如existingQuote ,nullish赋值运算符不做任何事情。然而,当在nonExistingQuote 上使用时,它会给引号分配一个新的值。
即使existingQuote 的字符串是空的(这在JavaScript中是一个虚假的值),nullish赋值也不会取代它;它仍然是一个空字符串。这就是操作符的本质:它只测试空或未定义。
和赋值(&&=)
和赋值运算符 (&&=) 测试表达式的左边。如果左边是真实的,它就赋值表达式的右边。 如果是虚假的,运算符就不做任何事情。清单6显示了一个简单的例子。
清单6.操作中的&&=赋值
let emptyString = "";
emptyString &&= "bar";
console.log (emptyString); // “”
let nonEmptyString = "foo";
nonEmptyString &&= "bar";
console.log(nonEmptyString); // “bar”
在清单6中,第一个控制台日志输出一个空字符串。这是因为空字符串是假的,所以&&= 操作符没有给它分配一个新的值。第二个控制台输出 "bar"。这是因为nonEmptyString 是 "foo",它是一个真实的值。
&&= 是一种边缘运算符,但在你需要它的时候很有用。
或赋值 (||=)
or赋值运算符与你刚才看到的 and赋值运算符相反。 我们可以使用清单6中的同一个例子,这次用||= 来代替&&= 。
清单7.运行中的||=赋值
let emptyString = "";
emptyString ||= "bar";
console.log (emptyString); // “bar”
let nonEmptyString = "foo";
nonEmptyString ||= "bar";
console.log(nonEmptyString); // “foo”
如果表达式的左边是假的,||= 赋值运算符会解析到右边。因此,在这个例子中,emptyString 变成了 "bar"。nonEmptyString 变量保持其真值 "foo"。
弱参考(WeakRef
WeakRef用来指代一个目标对象,而不使其免受垃圾收集的影响。 这是一个相当深奥的语言特性,工作中的代码员不常使用。WeakRef 的一个常见用例是在实现大型对象的缓存或映射时,"在这种情况下,人们希望一个大型对象不会仅仅因为它出现在缓存或映射中而被保留。"
因此,如果你发现自己正在为大型实体建立一个缓存解决方案,请记住WeakRef 的存在。否则,如果你不确定是否需要一个WeakRef 的变量引用,你可能应该避免使用它。(规范本身建议避免使用)。
最终化注册表
在Java废除Object.finalize()的时候,JavaScript几乎同时引入了FinalizationRegistry ,这在编程上是一个讽刺。这些功能实际上是类似的。就像WeakRef ,该规范警告开发者不要使用用户定义的终结器。
然而,对于某些用例,新的FinalizationRegistry 可能正是你所需要的。该规范提供了一个例子,即长期运行的进程会消耗许多文件句柄。 在这种情况下,使用FinalizationRegistry 可以确保没有句柄被泄露。
与WeakRef 一起,FinalizationRegistry 更适合于平台和框架开发者的工具箱,而不是应用开发者。
数字字面分隔符
数字分隔符是一个很好的东西,可以让人更容易看清大数字。JavaScript不能像自然语言那样使用逗号,因为这个符号已经被占用了。 所以,ECMAScript 2021引入了下划线。
不需要输入
let distanceToSun = 91772000000;
你可以输入
let distanceToSun = 91_772_000_000;
新的形式相当容易阅读。
Array.prototype.sort的改进
这与其说是一个特性,不如说是一个说明。基本上,ECMAScript 2021规范对Array.prototype.sort 的工作方式的描述更加精确。这一变化应该可以减少引擎之间的实现差异。