ECMAScript 2020(ES11)新特性简介
简介
ES2020
是 ECMA 协会在 2020 年 6 月发行的一个版本,因为是 ECMAScript 的第十一个版本,所以也称为 ES11.
今天我们讲解一下 ES11 的新特性。
ES11 引入了 9 个新特性,我们接下来一一讲解。
动态 imports
在 ES11 之前,我们可以使用下面的方式进行模块的导入:
import * as TestModule from "./test-module.js";
导入模块的现有语法形式为静态声明。它们接受字符串字面作为模块标识符,并通过运行前"链接"过程将绑定引入本地范围。可能会导致程序加载速度的降低。而且上面的模块名字是写死的,不可以在程序运行的时候进行动态修改。
为了解决这个问题,ES11 引入了新的import()
方法,使用这个方法,你可以对模块进行动态导入,并且通过设置模块名为变量的形式,可以对模块名进行动态修改,非常的神奇。我们看一个具体的使用例子:
const baseModulePath = "./baseModules";
const btn = document.getElementById("btn");
let userList = [];
btn.addEventListener("click", async () => {
const userModule = await import(`${baseModulePath}/users.js`);
userList = userModule.getUserList();
});
上面代码中我们定义了一个基本的 Module 路径,通过点击页面上的按钮,可以动态的加载一个users.js
模块,然后调用该模块的getUserList()
方法,获得用户列表。
import.meta
除了动态引入模块之外,import 还提供了一个元属性meta
,它包含了当前引入的模块的信息,目前他里面有一个 url 属性,代表模块被引用的 URL。如果想使用 URL 信息,那么可以在代码中使用import.meta.url
。
BigInt
ES11 引入了新的数据类型BigInt
,在这之前,javascript
中表示数字的对象是Number
,它可以表示64-bit
的浮点类型数字。当然它也可以代表整数,但是整数表示的最大值是2^53
,也可以用Number.MAX_SAFE_INTEGER
来表示。
一般来说 Number 已经够用了,但是如果在某些情况下需要对 64-bit 的整数进行存储或者运算,或者要表示的范围超过了 64-bit 的话,Number 就不够用了。
怎么办呢?如果只是存储的话,可以存储为字符串,但是第二种字符串就不适用了。于是引入了 BigInt 来解决这个问题。要表示 BigInt,只需要在数字的后面加上 n 即可。
const bigInt1 = 112233445566778899n;
const bigInt2 = BigInt("112233445566778899");
可以使用typeof
来查看bigInt
的类型。要注意的是虽然Number
和BigInt
都代表的是数字,但是两者是不能混用的,你不能将一个Number
和一个BigInt
相加。这会报TypeError
异常。
如果非要进行操作,那么可以使用 BigInt 构造函数将 Number 转换成为 BigInt 之后再进行。
String.prototype.matchAll()
matchAll
是match
的增强版,match
返回匹配的结果,matchAll
返回更加详细的匹配结果
const str = "abcdefga";
const reg = /a/g;
const result1 = str.match(reg);
/*
* result1
* ['a','a']
*/
const result2 = str.matchAll(reg);
/*
* result2
* [
* [ 'a', index: 0, input: 'abcdefga', groups: undefined ],
* [ 'a', index: 7, input: 'abcdefga', groups: undefined ]
* ]
*/
globalThis
对于 javascript 来说,不同的环境对应的全局对象的获取方式也是不同的,对于浏览器来说通常使用的是window
,但是在 web worker 中使用的是self
,而在 nodejs 中使用的是global
。
为了解决在不同环境中的全局对象不同的问题,ES11
引入了globalThis
,通过这个全局对象,程序员就不用再去区分到底是在哪个环境下了,只需要使用 globalThis 即可。
Promise.allSettled()
自从 Promise 引入之后,有两个方法可以对 Promise 进行组合,分别是Promise.all()
和Promise.race()
。
Promise.race()
:只要有一个resolve
就返回(返回最快执行的那个)Promise.all()
:它会等待所有的Promise
都运行完毕之后返回,如果其中有一个Promise
被rejected
,那么整个Promise.all()
都会被rejected
。在这种情况下,如果有一个 Promise 被 rejected,其他的 Promise 的结果也都获取不了。Promise.allSettled()
: 这个方法会等待所有的Promise
结束,不管他们是否被rejected
,所以可以获得所有的结果。
const promises = [fetch("index.html"), fetch("https://does-not-exist/")];
const results = await Promise.allSettled(promises);
const errors = results
.filter((p) => p.status === "rejected")
.map((p) => p.reason);
??
空值合并运算符
??
操作符是一个判断是否为空然后赋值的操作,如果没有这个操作符,我们通常使用||来简单的进行这个操作,如下所示:
const person = {
name: "Tom",
age: 18,
};
const yourAge = person.age || 18;
上面的代码意思是如果person.age
是空,那么就将yourAge
设置成为18
。
但是上面代码有个问题,如果 someBody.age=0 的话,上述逻辑也成立。使用??
操作符可以解决这个问题。
const person = {
name: "Tom",
age: 18,
};
const yourAge = person.age ?? 18;
?.
可选链操作符
我们有时候在获取某个对象的属性的时候,需要进行对象的 null 判断,否则从 null 对象中取出属性就会报错,但是通常的?:操作符使用起来太复杂了,如果有多个对象和属性连写的情况下更是如此,如果使用?.操作符就会简单很多:
const person = {
name: "Tom",
age: 18,
};
const age = person?.age;
如上所示,这个一个连写操作,但是使用?.
就变得很简单。
同样?.
还可以用在对象的方法上:
const person = {
name: "Tom",
age: 18,
getAge() {
return person.age;
},
};
const age = student.getAge?.();
上面代码表示,如果person
的getAge
方法存在,则调用,否则返回undefined
。
for-in
ECMAScript 遗留了 for-in
循环顺序的详尽介绍待填补。在 ES2020 中为 for-in
机制定义了一套规则。
参考
proposals/finished-proposals.md at master · tc39/proposals (github.com)