在写本文时,本文提到的新的 JavaScript 提案功能已进入第 4 阶段,而且几乎确定会包含在 ES2021 中。你已经能够开始在 最新版本的浏览器,Node.js 和 Babel 中使用。前端
注意:ECMAScript 是 JavaScript 所基于的标准,由 TC39 委员会管理。ECMAScript 始终是一个不须要的名称,这会使一切都对初学者感到困惑。人们常常谈论 JavaScript 功能,但参考的是 ECMAScript 规范。git
更新特性github
_
)&&=
,||=
,??=
)WeakRef
和FinalizationRegistry
)大数字文字很难令人眼快速解析,尤为是当有不少重复的数字时:正则表达式
1000000000000 1019436871.42
为了提升可读性,新的 JavaScript 语言功能 启用了下划线做为数字文字中的分隔符。所以,上面的内容如今能够重写为每千位数字,例如:编程
1_000_000_000_000 1_019_436_871.42
如今,更容易说出第一个数字是 1 万亿,而第二个数字大约是 10 亿。api
数字分隔符有助于提升各类数字文字的可读性:promise
// A decimal integer literal with its digits grouped per thousand: 1_000_000_000_000 // A decimal literal with its digits grouped per thousand: 1_000_000.220_720 // A binary integer literal with its bits grouped per octet: 0b01010110_00111000 // A binary integer literal with its bits grouped per nibble: 0b0101_0110_0011_1000 // A hexadecimal integer literal with its digits grouped by byte: 0x40_76_38_6A_73 // A BigInt literal with its digits grouped per thousand: 4_642_473_943_484_686_707n
它们甚至适用于八进制整数文字(尽管 我想不出 其中分隔符为此类文字提供值 的示例):浏览器
// A numeric separator in an octal integer literal: 🤷♀️ 0o123_456
请注意,JavaScript 还具备不带显式 0o
前缀的八进制文字的旧式语法。例如,017 === 0o17
。在严格模式下或模块内不支持此语法,而且在现代代码中不该使用此语法。所以,这些文字不支持数字分隔符。使用 0o17
风格的文字代替。babel
自从 ES2015 中引入 Promise 以来,JavaScript 彻底支持两种 Promise 组合器:静态方法 Promise.all 和 Promise.race。less
目前有两个新提案正在经过标准化流程:Promise.allSettled 和 Promise.any。有了这些添加,JavaScript 中将总共有四个诺言组合器,每一个组合器支持不一样的用例。
如下是这四个组合器的概述:
Promise.allSettled 给你当全部输入的诺言是一种信号结算,这意味着他们要么履行或拒绝。若是您不在意承诺的状态,而只是想知道工做什么时候完成,不管它是否成功,这都是颇有用的。
例如,您能够启动一系列独立的 API 调用,并使用 Promise.allSettled 它们来确保它们已所有完成,而后再执行其余操做,例如删除加载微调器:
const promises = [ fetch('/api-call-1'), fetch('/api-call-2'), fetch('/api-call-3'), ]; // Imagine some of these requests fail, and some succeed. await Promise.allSettled(promises); // All API calls have finished (either failed or succeeded). removeLoadingIndicator();
Promise.any
方法和 Promise.race
相似——只要给定的迭代中的一个 promise
成功,就采用第一个 promise
的值做为它的返回值,但与 Promise.race
的不一样之处在于——它会等到全部 promise
都失败以后,才返回失败的值:
const promises = [ fetch('/endpoint-a').then(() => 'a'), fetch('/endpoint-b').then(() => 'b'), fetch('/endpoint-c').then(() => 'c'), ]; try { const first = await Promise.any(promises); // Any of the promises was fulfilled. console.log(first); // → e.g. 'b' } catch (error) { // All of the promises were rejected. console.assert(error instanceof AggregateError); // Log the rejection values: console.log(error.errors); // → [ // <TypeError: Failed to fetch /endpoint-a>, // <TypeError: Failed to fetch /endpoint-b>, // <TypeError: Failed to fetch /endpoint-c> // ] }
此代码示例检查哪一个端点响应最快,而后将其记录下来。只有当 全部 请求都失败时,咱们才最终进入代码 catch
块,而后在其中处理错误。
Promise.any
拒绝能够一次表明多个错误。 为了在语言级别支持此功能,引入了一种新的错误类型,称为 AggregateError
。 除了上面示例中的基本用法外,还能够以编程方式构造 AggregateError
对象,就像其余错误类型同样:
const aggregateError = new AggregateError([errorA, errorB, errorC], 'Stuff went wrong!');
此功能包含两个高级对象 WeakRef
和 FinalizationRegistry
。根据使用状况,这些接口能够单独使用,也能够一块儿使用。正确使用它们须要仔细考虑,若是可能,最好避免使用它们。
通常来讲,在JavaScript中,对象的引用是强保留的,这意味着只要持有对象的引用,它就不会被垃圾回收。
const ref = { x: 42, y: 51 }; // 只要咱们访问 ref 对象(或者任何其余引用指向该对象),这个对象就不会被垃圾回收
目前在 Javascript 中,WeakMap 和 WeakSet 是弱引用对象的惟一方法:将对象做为键添加到 WeakMap 或 WeakSet 中,是不会阻止它被垃圾回收的。
JavaScript 的 WeakMap 并非真正意义上的弱引用:实际上,只要键仍然存活,它就强引用其内容。WeakMap 仅在键被垃圾回收以后,才弱引用它的内容。
WeakRef 是一个更高级的 API,它提供了真正的弱引用,Weakref 实例具备一个方法 deref,该方法返回被引用的原始对象,若是原始对象已被收集,则返回 undefined 对象。
JavaScript 中对象的引用是强引用,WeakMap 和 WeakSet 能够提供部分的弱引用功能,若想在 JavaScript 中实现真正的弱引用,能够经过配合使用 WeakRef 和终结器(Finalizer)来实现。
WeakRef 是用来指目标对象不脱离垃圾收集保留它的对象。若是未经过垃圾回收回收目标对象,则 WeakRefs 能够取消引用以容许访问目标对象。
// Create a WeakRef object referring to a given target object const ref = new WeakRef(targetObject) // Return the WeakRef instance's target object, or undefined if the target object has been garbage-collected const obj = ref.deref()
使用 FinalizationRegistry 对象能够在垃圾回收对象时请求回调。
// Create a registry object that uses the given callback const registry = new FinalizationRegistry([callback]) // Register an object with a registry instance so that if the object is garbage-collected, the registry's callback may get called registry.register(target, heldValue, [unregisterToken]) // Unregister a target object from a registry instance registry.unregister(unregisterToken)
当前,若是不使用全局正则表达式,就没法替换字符串中子字符串的全部实例。与字符串参数一块儿使用时,String.prototype.replace 仅影响首次出现。
String.prototype.replaceAll()
将为开发人员提供一种简单的方法来完成此常见的基本操做。
'aabbcc'.replaceAll('b', '.') // 'aa..cc' 'aabbcc'.replaceAll(/b/g, '.') // 'aa..cc'
支持与新的运营逻辑分配 &&=
,||=
和 ??=
。与它们的 数学和按位对应物不一样,逻辑分配遵循其各自逻辑操做的短路行为。仅当逻辑运算将评估右侧时,它们才执行分配。
// falsy: false, 0, -0, 0n, "", null, undefined, and NaN // truthy: all values are truthy unless defined as falsy // nullish: null or undefined a ||= b // Logical OR assignment // Equivalent to: a || (a = b); // Only assigns if a is falsy a &&= b // Logical AND assignment // Equivalent to: a && (a = b); // Only assigns if a is truthy a ??= b // Logical nullish assignment // Equivalent to: a ?? (a = b); // Only assigns if a is nullish
带有 &&
运算符的逻辑赋值运算符
仅当 LHS 值为真时,才将 RHS 变量值赋给 LHS 变量。
// Logical Assignment Operator with && operator let num1 = 5 let num2 = 10 num1 &&= num2 console.log(num1) // 10 // Line 5 can also be written as following ways // 1. num1 && (num1 = num2) // 2. if (num1) num1 = num2
带有 ||
的运算符逻辑赋值运算符
仅当 LHS 值为假时,才将 RHS 变量值赋给 LHS 变量。
// Logical Assignment Operator with || operator let num1 let num2 = 10 num1 ||= num2 console.log(num1) // 10 // Line 5 can also be written as following ways // 1. num1 || (num1 = num2) // 2. if (!num1) num1 = num2
带有 ??
运算符的逻辑赋值运算符
ES2020 引入了空值合并运算符,其也能够与赋值运算符结合使用。
仅当 LHS 为 undefined 或仅为 null 时,才将 RHS 变量值赋给 LHS 变量。
// Logical Assignment Operator with ?? operator let num1 let num2 = 10 num1 ??= num2 console.log(num1) // 10 num1 = false num1 ??= num2 console.log(num1) // false // Line 5 can also be written as following ways // num1 ?? (num1 = num2)
做为开发人员,跟紧语言的新特性是很重要的。
以上将在 2021 年发布的一些新功能,它们是进入第 4 阶段的提案,几乎能够确定会包括在内,这些功能已经在最新的浏览器和 babel 中实现。
欢迎关注公众号: “全栈修炼”,回复 “电子书” 便可以得到 160 本前端精华书籍哦。
参考文章:JavaScript Features in 2021
往期精文
经过阅读本篇文章,若是有收获的话,能够点个赞和在看,这将会成为我持续分享的动力,感谢~