回顾这些年EcmaScript标准中引入的新特性:ES2020
接续介绍,本文介绍ES2020引入的特性,如下:
String实例上引入matchAll方法
import()语法
数值类型BigInt
Promise.allSettled
globalThis
export * as ns from 'module'语法
增加了对for in 枚举顺序的标准
import.meta
新增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中的动态导入功能,满足了一些场景的需要:
<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
viaInternalizeJSONProperty
JSON.stringify
viaSerializeJSONObject
以下API是和Reflect.ownKeys序一样的,内部是通过调用[[OwnPropertyKeys]]方法:
Reflect.ownKeys
Object.getOwnPropertyNames
(viaGetOwnPropertyKeys
)Object.getOwnPropertySymbols
(viaGetOwnPropertyKeys
)Object.assign
Object.create
(viaObjectDefineProperties
)Object.defineProperties
viaObjectDefineProperties
Object.getOwnPropertyDescriptors
Object.freeze
(viaSetIntegrityLevel
)Object.seal
(viaSetIntegrityLevel
)Object.isFrozen
(viaTestIntegrityLevel
)Object.isSealed
(viaTestIntegrityLevel
)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.js
import.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 data
const usage2 = obj.data ?? 'some other num' // 0
// ?.可选链式访问,只有?前面的对象不为nullish时才会继续执行后面的
// 属性访问,否则返回一个undefined
const usage3 = obj.x.y // 报错
const usage4 = obj.x?.y // undefined
const usage5 = obj.x.z() // undefined