ECMAScript2020是ECMAScript语言规范的第十一版。自1997年第一版出版以来,ECMAScript已经发展成为世界上使用最广泛的通用编程语言之一。ES2020(ES11)引入了以下新特性:String的matchAll方法动态导入语句import()import.metaexport*asnsfrom'module'Promise.allSettled新数据类型:BigIntGlobalThisNullishcoalescingOperatorOptionalChainingmatchAllmatchAll()方法返回一个包含与正则表达式匹配的所有结果的迭代器。使用for...of对其进行迭代或使用运算符...Array.from将其转换为数组。constreg=/[0-3]/g;constdata='2020';console.log(data.matchAll(reg));//data.matchAll的返回值是一个迭代器console.log([...data.matchAll(reg)]);/***0:["2",index:0,input:"2020",groups:undefined]*1:["0",index:1,input:"2020",groups:undefined]*2:["2",index:2,input:"2020",groups:undefined]*3:["0",index:3,input:"2020",groups:undefined]*/动态导入标准用法import的导入模块是静态的,会导致所有引入的模块加载时编译(不能按需编译,降低首页加载速度)。在某些场景下,您可能希望有条件地或按需导入模块,那么您可以使用动态导入而不是静态导入。在import()之前,当我们需要有条件地导入模块时,我们必须使用require()。例如:if(XXX){constmenu=require('./menu');}现在可以替换为:if(XXX){constmenu=import('./menu');}@babel/preset-envalready包含@babel/plugin-syntax-dynamic-import,所以如果要使用import()语法,只需要配置@babel/preset-env。提示:不要滥用动态导入(仅在必要时)。静态框架可以更好的初始化依赖,更有利于静态分析工具和treeshaking。此外,import()返回一个promise对象。例如://menu.jsexportdefault{menu:'menu'}//index.jsif(true){letmenu=import('./menu');console.log(menu);//Promise{menu.then(data=>console.log(data));//Module{default:{menu:"menu"},__esModule:true,Symbol(Symbol.toStringTag):"Module"}}else{}import.metaimport.meta会返回一个带有url属性的对象,返回当前模块的url路径,只能在模块内部使用。//main.jsconsole.log(import.meta);//{url:"http://localhost:8080/main.js"}PS:使用它是因为import.meta必须在模块内部使用。如果不加type="module",控制台会报错:Cannotuse'import.meta'outsideamodule。测试之初,我在一个React项目中进行了测试。我只配置了@babel/preset-env和@babel/preset-react预设。使用import.meta时会报错如下:安装@open-wc/webpack-import-meta-loader,修改webpack的配置,可以正常运行。模块:{规则:[{测试:/\.js$/,使用:[re??quire.resolve('@open-wc/webpack-import-meta-loader'),{loader:'babel-loader',选项:{presets:["@babel/preset-env","@babel/preset-react"]},}]}]}效果如下://src/index.jsimportReactfrom'react';console.log(import.meta);//{index.js:38{url:"http://127.0.0.1:3000/src/index.js"}}export*asnsfrom'module'ES2020addedexport*asXXfrom'module',andimport*asXXfrom'module'//menu.jsexport*asnsfrom'./info';可以理解为将下面两条语句合为一句话:import*asnsfrom'./info';export{ns};但是需要注意的是,export*asnsfrom'./info'并不会真正导入模块,所以在这个模块(menu.js)中,我们是无法获取到ns的。Promise.allSettledPromise.all或Promise.race有时并不能满足我们的需求。例如,我们需要在所有promise都resolve时做一些事情,不管它们是成功还是失败。在没有Promise.allSettled之前,我们需要自己写实现。Promise.allSettled()方法在所有给定的承诺已被履行或拒绝后返回一个承诺,其中包含一个对象数组,每个对象代表相应的承诺结果。constpromise1=Promise.resolve(100);constpromise2=newPromise((resolve,reject)=>setTimeout(reject,100,'info'));constpromise3=newPromise((resolve,reject)=>setTimeout(resolve,200,'名称'))Promise.allSettled([promise1,promise2,promise3]).then((results)=>console.log(result));/*[{status:'fulfilled',value:100},{status:'rejected',reason:'info'},{status:'fulfilled',value:'name'}]*/可以看到Promise.allSettled()成功的结果是一个数组,数组的每一项是一个对象,每个对象都有一个status属性,值为fulfilled或者rejected,如果status的值为fulfilled,那么这个对象也有一个value属性,它的属性值就是对应的promise成功的结果;如果status的值为rejected,则该对象具有reason属性,其值是相应承诺失败的原因。BigIntBigInt是一种数字数据类型,可以表示任意精度格式的整数。在此之前,JS中最大安全数为9009199254740991,即2^53-1,在控制台输入Number.MAX_SAFE_INTEGER即可查看。超出这个值,JS没办法准确表示。另外,JS不能表示大于等于2的1024次方的值,会返回Infinity。BigInt解决了这两个问题。BigInt仅用于表示整数,没有位数限制,可以准确表示任意位数的整数。为了区别于Number类型,BigInt类型的数据必须加上后缀n。//Number类型超过9009199254740991后,计算结果会有问题constnum1=90091992547409910;console.log(num1+1);//90091992547409900//BigInt计算结果争取constnum2=90091992547409910n;console.log(num2+1n);//90091992547409911n//Number类型不能表示大于2的1024次方的值letnum3=9999;for(leti=0;i<10;i++){num3num3=num3*num3;}console.log(num3);//Infinity//BigInt类型可以表示任意位数的整数letnum4=9999n;for(leti=0n;i<10n;i++){num4num4=num4*num4;}console.log(num4);//一串超长的数字,这里就不贴了我们也可以使用BigInt对象来初始化BigInt实例:console.log(BigInt(999));//999n注意:没有新关键字!!!需要注意的是,BigInt和Number是两种数据类型,不能直接进行四次算术运算,但是可以进行比较运算。console.log(99n==99);//trueconsole.log(99n===99);//falseconsole.log(99n+1);//TypeError:CannotmixBigIntandothertypes,useexplicitconversionssGlobalThisJS有顶层对象,不过,顶级对象在实现中并不统一。从不同的JavaScript环境中检索全局对象需要不同的语句。在Web中,可以通过window和self获取全局对象,而在WebWorkers中,只有self可以。在Node.js中,它们都不可取,必须使用global。在globalThis之前,我们得到这样的全局对象:='undefined'){returnglobal;}thrownewError('unabletolocateglobalobject');};ES2020引入了globalThis作为顶级对象。在任何环境下,您都可以通过globalThis简单地获取顶级对象。NullishcoalescingOperatorES2020添加了一个新的运算符??。当左操作数为null或undefined时,返回右操作数,否则返回左操作数。使用||运算符,当左边的操作数为0、null、undefined、NaN、false、''时,将使用右边的操作数。如果你使用||为某些变量设置默认值,您可能会遇到意想不到的行为。例如:constdefaultValue=100;letvalue=someValue||defaultValue;//当someValue转boolean值为false时,value的值为defaultValue。当someValue的值为0时,我们其实期望值是0,但它被错误地赋值为100。??运营商可以规避上述问题。只有当左操作数为空或未定义时,它才会返回右操作数。constdefaultValue=100;letvalue=someValue||defaultValue;//someValue为0,value的值为0OptionalChainingoptionalchainoperator?.允许读取位于连接对象链深处的属性值,而不必显式验证链中的每个引用是否有效。?的功能。运算符类似于.连锁经营者。不同的是当引用为空(nullish,即null或undefined)时不会报错,而这个表达式的短路返回值是undefined。例如,我们要访问info对象的动物的爬行动物的乌龟。但是我们不确定animal,reptile是否存在,所以需要这样写:consttortoise=info.animal&&info.animal.reptile&&info.animal.reptile.tortoise;因为null.reptile或者undefined.reptile会报错:TypeError:Cannotreadproperty'reptile'ofundefined或者TypeError:Cannotreadproperty'reptile'ofnull,为了避免报错,如果我们需要访问的属性是越深,那么这行代码就会越来越长。使用可选的链接运算符?.,我们不再需要在访问爬行动物之前验证info.animal的值。此外,在访问info.animal.reptile.tortoise之前无需验证info.animal.reptile的值。上面的代码简化为:consttortoise=info.animal?.reptile?.tortoise;JS在尝试访问info.animal.reptile之前会隐式检查并判断info.animal的值不为null或undefined,如果其值为null或undefined,则表达式短路计算直接返回undefined。您可以看到可选链运算符?。和空合并运算符一样,都是针对null和undefined这两个值。至此,ES2020的新特性介绍完毕。总的来说,新加的不多,一杯咖啡就能大概了解,但还是要经常温习一下,不然很容易忘记。