百科狗-知识改变命运!
--

ECMAScript 2020(ES11)新特性 - Es6+ 版本特性

乐乐1年前 (2023-11-21)阅读数 11#技术干货
文章标签模块

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

ECMAScript 2020(ES11)新特性 - Es6+ 版本特性

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

免责声明:我们致力于保护作者版权,注重分享,当前被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理!邮箱:344225443@qq.com)

图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

内容声明:本文中引用的各种信息及资料(包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主体(包括但不限于公司、媒体、协会等机构)的官方网站或公开发表的信息。部分内容参考包括:(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供参考使用,不准确地方联系删除处理!本站为非盈利性质站点,本着为中国教育事业出一份力,发布内容不收取任何费用也不接任何广告!)