ECMAScript 2020(ES11)新特性 - Es6+ 版本特性
ECMAScript 2020(ES11)新特性
ECMAScript 2020(ES11)新特性:
??
操作符?.
操作符- 导出加强:export。
- 动态导入:await import()。
- 元信息:import.meta。
- 等待所有的 Promise 结束:Promise.allSettled()。
- 正则模式:matchAll()。
- 任意精度的整数:BigInt。
- 标准化对象:globalThis。
??操作符
??
操作符是一个判断是否为空然后赋值的操作,如果没有这个操作符,我们通常使用||
来简单的进行这个操作,如下所示:
const yourAge = someBody.age || 18
上面的代码意思是如果someBody.age是空,那么就将yourAge设置成为 18。但是上面代码有个问题,如果 someBody.age=0 的话,上述逻辑也成立。使用??
操作符可以解决这个问题。
const yourAge = someBody.age ?? 18
?.操作符
我们有时候在获取某个对象的属性的时候,需要进行对象的null
判断,否则从null
对象中取出属性就会报错,但是通常的?:
操作符使用起来太复杂了,如果有多个对象和属性连写的情况下更是如此,如果使用?.
操作符就会简单很多:
const age = school?.class?.student?.age;
同样?.
还可以用在对象的方法上:
const age = student.getAge?.();
上面代码表示,如果student的getAge()
方法存在,则调用,否则返回undefined
。
动态导入
在 ES11 之前,我们可以使用下面的方式进行模块的导入:
import * as TestModule from "./test-module.js";
但是上面的导入方式会有一些问题,首先是效率的问题,所有的 module 都需要在首次加载的时候导入,会导致程序效率的降低。另外上面的模块名字是写死的,不可以在程序运行的时候进行动态修改。也就是说上面的模块导入方式,不能对模块进行动态导入,或者按需导入,在使用上有诸多的不便。
为了解决这个问题,ES11 引入了新的import()
方法,使用这个方法,你可以对模块进行动态导入,并且通过设置模块名为变量的形式,可以对模块名进行动态修改。动态导入返回请求模块的模块名称空间对象的 promise 。因此,可以配合使用 async/await。
const baseModulePath = "./baseModules"; const btnImportModule = document.getElementById("btnImportModule"); let userList = []; btnImportModule.addEventListener("click", async e => { const userModule = await import(`${baseModulePath}/users.js`); userList = userModule.getUsers(); });
element.addEventListener('click', async() => { const module = await import(`./api-scripts/button-click.js`); module.clickEvent(); })
import.meta
除了动态引入模块之外,import 还提供了一个元属性meta
,它包含了当前引入的模块的信息,目前他里面有一个 url 属性,代表模块被引用的 URL。如果想使用 URL 信息,那么可以在代码中使用import.meta.url
。
import.meta
,返回当前模块的元信息。import.meta
只能在模块内部使用,如果在模块外部使用会报错。这个属性返回一个对象,该对象的各种属性就是当前运行的脚本的元信息。具体包含哪些属性,标准没有规定,由各个运行环境自行决定。一般来说,import.meta
至少会有下面两个属性。
import.meta.url
import.meta.url
返回当前模块的 URL 路径。举例来说,当前模块主文件的路径是https://foo.com/main.js,import.meta.url
就返回这个路径。如果模块里面还有一个数据文件data.txt,那么就可以用下面的代码,获取这个数据文件的路径。
new URL('data.txt', import.meta.url)
注意,Node.js 环境中,import.meta.url
返回的总是本地路径,即是file:URL
协议的字符串,比如file:///home/user/foo.js。
import.meta.scriptElement
import.meta.scriptElement
是浏览器特有的元属性,返回加载模块的那个>元素,相当于
document.currentScript
属性。
// HTML // // my-module.js 内部执行下面的代码 import.meta.scriptElement.dataset.foo // "abc"
export 加强
对于导出模块需要重命名的情况,我们不能直接导出,而是必须先在import
的时候进行重命名,然后再使用export
将重命名的模块导出:
import * as myModule from "./test-module.js"; export {myModule};
如果使用export
的增强,则不需要使用import
,直接使用export
导出即可:
export * as {myModule} from "./test-module.js";
Promise.allSettled()
自从 Promise 引入之后,有两个方法可以对 Promise 进行组合,分别是Promise.all()
和Promise.race()
,他们分别表示返回所有的 Promise 和返回最快的那个。
对于Promise.all()
来说,它会等待所有的 Promise 都运行完毕之后返回,如果其中有一个 Promise 被 rejected,那么整个Promise.all()
都会被 rejected。在这种情况下,如果有一个 Promise 被 rejected,其他的 Promise 的结果也都获取不了。
为了解决这个问题,ES11 引入了Promise.allSettled()
方法,这个方法会等待所有的 Promise 结束,不管他们是否被 rejected。
const promises = [promise1("/do1"), promise2("/do2")]; const allResults = await Promise.allSettled(promises); const errors = results .filter(p => p.status === 'rejected') .map(p => p.reason);
String.protype.matchAll()
以前,带字符串参数的String.match()
仅返回第一个匹配。
let string = 'Between'; let matches = string.match('e'); console.log(matches[0]); // "e"
添加/g
模式:
let string = 'Between'; let ret = string.match(/e/g); // (3) ["e","e","e"];
ES11 引入了matchAll()
方法。这个方法可以简单的返回一个遍历器,通过遍历这个遍历器,就可以得到所有的匹配的值,如下所示:
const regExp = /yyds(\d+)/g; const text = 'yyds1 is a very good yyds2'; let matches = [...text.matchAll(regExp)]; for (const match of matches) { console.log(match); }
使用.matchAll()
的好理由:
- 在与捕获组一起使用时,它可以更加优雅,捕获组只是使用
()
提取模式的正则表达式的一部分。 - 它返回一个迭代器而不是一个数组,迭代器本身是有用的。
- 迭代器可以使用扩展运算符(
…
)转换为数组。 - 它避免了带有
/g
标志的正则表达式,当从数据库或外部源检索未知正则表达式并与陈旧的 RegEx 对象一起使用时,它非常有用。 - 使用 RegEx 对象创建的正则表达式不能使用点(
.
)操作符链接。 - 高级: RegEx 对象更改跟踪最后匹配位置的内部
.lastindex
属性,这在复杂的情况下会造成严重破坏。
const string = 'black*raven lime*parrot white*seagull'; const regex = /(?.*?)\*(?[a-z0-9]+)/; for (const match of string.matchAll(regex)) { let value = match[0]; let index = match.index; let input = match.input; console.log(`${value} at ${index} with '${input}'`); console.log(match.groups.color); console.log(match.groups.bird); }
BigInt
ES11 引入了新的数据类型 BigInt,在这之前,javascript 中表示数字的对象是Number
,它可以表示 64-bit 的浮点类型数字。当然它也可以代表整数,但是整数表示的最大值是2^53
,也可以用Number.MAX_SAFE_INTEGER
来表示。
一般来说Number已经够用了,但是如果在某些情况下需要对 64-bit 的整数进行存储或者运算,或者要表示的范围超过了 64-bit 的话,Number 就不够用了。怎么办呢?如果只是存储的话,可以存储为字符串,但是第二种字符串就不适用了。于是引入了BigInt来解决这个问题。要表示 BigInt,只需要在数字的后面加上n
即可。
BigInt 是第七种原始类型。BigInt 是一个任意精度的整数。这意味着变量现在可以表示²⁵³
数字,而不仅仅是 9007199254740992。
const bigInt = 112233445566778899n;
或者使用构造函数来构造 bigInt:
const bigInt = BigInt("112233445566778899");
可以使用typeof
来查看 bigInt 的类型。要注意的是虽然Number和BigInt都代表的是数字,但是两者是不能混用的,你不能将一个 Number 和一个 BigInt 相加。这会报 TypeError 异常。如果非要进行操作,那么可以使用 BigInt 构造函数将 Number 转换成为 BigInt 之后再进行。
const b = 1n; // 追加 n 以创建 BigInt
在过去,不支持大于 9007199254740992 的整数值。如果超过,该值将锁定为 MAX_SAFE_INTEGER + 1:
const limit = Number.MAX_SAFE_INTEGER; // 9007199254740991 limit + 1; // 9007199254740992 limit + 2; // 9007199254740992
鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com
图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!