vlambda博客
学习文章列表

回顾这些年EcmaScript标准中引入的新特性:ES2020

接续介绍,本文介绍ES2020引入的特性,如下:

  1. String实例上引入matchAll方法

  2. import()语法

  3. 数值类型BigInt

  4. Promise.allSettled

  5. globalThis

  6. export * as ns from 'module'语法

  7. 增加了对for in 枚举顺序的标准

  8. import.meta

  9. 新增2个语法处理nullish(undefined或者null)的情况:?? 和 ?.


下面详解介绍一下上述特性:


String.prototype.match并不会返回捕获组,有些场景下显得乏力,matchAll方法返回一个迭代器,从中可以获取所有的匹配,包括捕获组。

var regex = /t(e)(st(\d?))/g;var string = 'test1test2';
string.match(regex); // ['test1', 'test2']Array.from(string.matchAll(regex)) //

import()提供了在script和module中的动态导入功能,满足了一些场景的需要:

<!DOCTYPE html><nav> <a href="books.html" data-entry-module="books">Books</a> <a href="movies.html" data-entry-module="movies">Movies</a> <a href="video-games.html" data-entry-module="video-games">Video Games</a></nav>
<main>Content will load here!</main>
<script> const main = document.querySelector("main"); for (const link of document.querySelectorAll("nav > a")) { link.addEventListener("click", e => { e.preventDefault();
import(`./section-modules/${link.dataset.entryModule}.js`) .then(module => { module.loadPageInto(main); }) .catch(err => { main.textContent = err.message; }); }); }</script>


BigInt可以表示大于2^53的数值而不丢失精度,书写方式为数值后面跟一个n

const x = Number.MAX_SAFE_INTEGER;// ↪ 9007199254740991, this is 1 less than 2^53
const y = x + 1;// ↪ 9007199254740992, ok, checks out
const z = x + 2// ↪ 9007199254740992, wait, that’s the same as above!

BigInt可以像Number数据类型一样进行运算,但除了除法 /,因为BigInt会取整

const expected = 4n / 2n;// ↪ 2n
const rounded = 5n / 2n;// ↪ 2n, not 2.5n

还有一些其他限制,如不能和Number类型的进行混合运算,BigInt前面不能有+号等等,详见https://github.com/tc39/proposal-bigint#gotchas--exceptions。


Promise.allSettled的使用场景是在多个请求之后执行操作,且等待所有请求完成时执行。它返回一个Promise,只有当所有原始的Promise已经settled时为fullfilled,无论它们是fullfilled还是rejected。

const urls = [ /* ... */ ];const requests = urls.map(x => fetch(x));// We know all API calls have finished. // We use finally but allSettled will never reject.Promise.allSettled(requests).finally(() => { console.log('All requests are completed: either failed or succeeded, I don’t care'); removeLoadingIndicator();});


为了在不同环境下都能拿到顶层的this对象,引入了标准化的globalThis,但在HTML中,由于iframe及跨窗口安全性的考虑,顶层对象以window和windowProxy的方式隔离开了,此时globalThis实际指向的是windowProxy,详见https://github.com/tc39/proposal-global#html-and-the-windowproxy。


为了方便以声明式的方式构建package module,增加了语法:

// 将mod中的所有导出放在someName命名空间下重新导出export * as someName from 'mod'


一直以来,规范都没有详细规定for in遍历时属性的顺序,现实中的JS引擎(V8, SpiderMonkey, ChakraCore, JavaScriptCore, XS)倾向于在一些场景下提供一致的实现。历史上为做出一个完整的for-in顺序的努力都失败了,现在一个JS引擎都认可的保守的交互语义如下:

  • Neither the object being iterated nor anything in its prototype chain is a proxy, typed array, module namespace object, or host exotic object.

  • Neither the object nor anything in its prototype chain has its prototype change during iteration.

  • Neither the object nor anything in its prototype chain has a property deleted during iteration.

  • Nothing in the object's prototype chain has a property added during iteration.

  • No property of the object or anything in its prototype chain has its enumerability change during iteration.

  • No non-enumerable property shadows an enumerable one.

以上只是针对和for-in内部实现一样的api(通过调用EnumerableOwnPropertyNames方法):

  • Object.keys

  • Object.values

  • Object.entries

  • JSON.parse via InternalizeJSONProperty

  • JSON.stringify via SerializeJSONObject

以下API是和Reflect.ownKeys序一样的,内部是通过调用[[OwnPropertyKeys]]方法:

  • Reflect.ownKeys

  • Object.getOwnPropertyNames (via GetOwnPropertyKeys)

  • Object.getOwnPropertySymbols (via GetOwnPropertyKeys)

  • Object.assign

  • Object.create (via ObjectDefineProperties)

  • Object.defineProperties via ObjectDefineProperties

  • Object.getOwnPropertyDescriptors

  • Object.freeze (via SetIntegrityLevel)

  • Object.seal (via SetIntegrityLevel)

  • Object.isFrozen (via TestIntegrityLevel)

  • Object.isSealed (via TestIntegrityLevel)

  • object spread (via CopyDataProperties)

  • object rest in both assignment and binding position (via CopyDataProperties)


为了针对宿主环境,提供特定模块的信息,引入import.meta

// <script type="module" src="path/to/some.mjs" data-size="500" />
// some.jsimport.meta.srciptElement.dataset.size // 500// meta上面可以挂载其他信息,如vite使用import.meta.hot对象暴露HMR// 相关API


为了提升使用nullish的体验,引入了?? 和?.操作符

const obj = { prop: null, data: 0}// ??操作符,只有左边是null或者undefined的情况下才会返回右边const usage1 = obj.prop ?? 'some other data' // some other dataconst usage2 = obj.data ?? 'some other num' // 0
// ?.可选链式访问,只有?前面的对象不为nullish时才会继续执行后面的// 属性访问,否则返回一个undefinedconst usage3 = obj.x.y // 报错const usage4 = obj.x?.y // undefinedconst usage5 = obj.x.z() // undefined