What's new in ECMAScript 2020 (ES2020)
从 ES2016 开始,ECMA 修改了标准的制定原则:成文标准要从事实标准中诞生,实现先于标准存在,进入标准草案必须有 JavaScript 引擎实现的支持、社区里有充分的人气和足够的 Test262 测试。
旨在通过更频繁地发布小规模增量更新,促进标准和语言的快速发展,而版本命令规则使用 ECMAScript + 年份的形式。
所以,我们今年又可以看看 ES2020 新增了哪些特性啦。✌️
动态 import
如果你有某个在代码中不常使用的资源,直接导入其所有依赖项可能只是浪费资源的话。我们就可以在需要时通过 async/await
动态导入该依赖项。
新的动态 import
语法看起来像一个函数,但并不是函数,不过动态 import
语法也支持 await
。
1 | // math.js |
1 | // index.js |
在这之前,我们通常会借助 require.ensure()
来实现该特性。
1 | // index.js |
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/import
私有 Class 变量
Class 属性在默认情况下是公共的,可以被外部类检测或修改。现在你可以 #
前缀来定义私有类字段。
1 | class Message { |
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/Private_class_fields
Promise.allSettled
该 Promise.allSettled()
方法返回一个在所有给定的 promise 已被决议或被拒绝后决议的 Promise
,并带有一个对象数组 [{status, ?value, ?reason}]
,每个对象表示对应的 promise 结果。
1 | const p1 = Promise.resolve(1); |
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
空值合并运算符
大家都知道由于 JavaScript 是动态类型的,在进行某些比较操作的时候经常会发生一些「隐式强制转换」,导致我们最终获取到的结果跟我们的预期不一致。例如下面这种情况,我们期望有效值的内容可以被正常打印出来:
1 | let person = { |
如果我们希望该判断条件更加严格点的话,只有值为 null
或 undefined
时才允许使用默认值,就得改成这种操作:
1 | const { name, age } = person.profile; |
ES2020 引入了一个新的运算符 ??
,该运算符的工作原理与上述的条件一致,仅当初始值为 null
或 undefined
时才读取为运算符右边的值。
1 | console.log(person.profile.name ?? 'Anonymous'); // '' |
可选链操作符
与空值合并运算符相似,JavaScript 处理假值时可能无法按照我们的意愿行事。如果我们想要的值是不确定的,我们可以返回一个默认值。但是如果它的路径是不确定的,该怎么办?
可选链操作符 ?.
可以按照操作符之前的属性是否有效,链式读取对象的属性或者使整个对象链返回 undefined
。 ?.
运算符的作用与 .
运算符类似,不同之处在于,如果对象链上的引用是 nullish
(null
或者 undefined
),.
操作符会抛出一个错误,而 ?.
操作符则会按照短路计算的方式进行处理,返回 undefined
。
1 | const adventurer = { |
可选链操作符也可用于函数调用,如果操作符前的函数不存在,也将会返回 undefined。
1 | console.log(adventurer.someNonExistentMethod?.()); // undefined |
结合其他运算符一起使用,效果更佳:
1 | let person = {}; |
BigInt
BigInt 是一个内置的对象,它提供了一种方法来表示大于 2⁵³-1
的整数,这是 JavaScript 可以可靠地用 number 原语表示的最大数,并由 number 表示。MAX_SAFE_INTEGER
常量。BigInt 可用于任意大整数。
1 | const max = Number.MAX_SAFE_INTEGER; |
超过此该值后,一切操作就开始变得有点奇怪…
1 | console.log(max + 1); // 9007199254740992 |
现在我们可以使用新的 BigInt 数据类型解决此问题。通过在末尾加上字母 n
,就可以创建一个 BigInt 类型的数据。我们无法将标准数字与 BigInt 数字混合使用,因此任何数学运算都需要使用BigInt 来完成。
1 | const bigNum = 100000000000000000000000000000n; |
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/BigInt
globalThis
在 JavaScript 中,编写可跨平台的访问全局对象的代码特别麻烦。在浏览器环境下,我们会通过 window
、self
、this
、frames
等各种方式来访问;在 Node 环境下,我们又会通过 global
或者 this
来访问;其中,只有 V8 的 d8
或者 JavaScriptCore 的 jsc
之类的 shell 中才会提供访问全局对象的功能。
在松散模式下,可以在函数中返回 this
来获取全局对象,但是在严格模式和模块环境下,this
会返回 undefined
。获取环境全局对象的唯一可靠的跨平台方法是 Function('return this')()
。但是这在某些情况下会违反 CSP 规则(例如在 Chrome Apps中),因此 es6-shim 使用了类似如下的方式:
1 | var getGlobal = function () { |
globalThis
提供了一个标准的方式来获取不同环境下的全局 this
对象(也就是全局对象自身)。不像 window
或者 self
这些属性,它确保可以在有无窗口的各种环境下正常工作。所以,你可以安心的使用 globalThis
,不必担心它的运行环境。为便于记忆,你只需要记住,全局作用域中的 this
就是 globalThis
。有了这个功能,就不再需要在整个环境中进行全局搜索了:
1 | if (typeof globalThis.foo !== 'function') { |
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/globalThis
延伸阅读
https://github.com/tc39/proposals/blob/master/finished-proposals.md