ES2020 新特性(种草)
这几年,EcmaTC39一年一次更新ecmascript规范标准,截止目前,以下特性已进入finished状态。现在带大家体验种草ES2020新特性。
一:Promise.allSettled
Promise.all缺陷
都知道Promise.all具有并发执行异步任务的能力。但它的最大问题就是如果其中某个任务出现异常(reject),所有任务都会挂掉,Promise直接进入reject 状态。
想象这个场景:你的页面有三个区域,分别对应三个独立的接口数据,使用Promise.all来并发三个接口,如果其中任意一个接口服务异常,状态是reject,这会导致页面中该三个区域数据全都无法渲染出来,因为任何reject都会进入catch回调,很明显,这是无法接受的,如下:
Promise.all([ Promise.reject({code:500,msg:'服务异常'}), Promise.resolve({code:200,list:[]}), Promise.resolve({code:200,list:[]}) ]) .then((ret)=>{ //如果其中一个任务是reject,则不会执行到这个回调。 RenderContent(ret); }) .catch((error)=>{ //本例中会执行到这个回调 //error:{code:500,msg:"服务异常"} })
我们需要一种机制,如果并发任务中,无论一个任务正常或者异常,都会返回对应的的状态(fulfilled或者rejected)与结果(业务value或者拒因reason),在then里面通过filter来过滤出想要的业务逻辑结果,这就能最大限度的保障业务当前状态的可访问性,而Promise.allSettled就是解决这问题的。
Promise.allSettled([ Promise.reject({code:500,msg:'服务异常'}), Promise.resolve({code:200,list:[]}), Promise.resolve({code:200,list:[]}) ]) .then((ret)=>{ /* 0:{status:"rejected",reason:{…}} 1:{status:"fulfilled",value:{…}} 2:{status:"fulfilled",value:{…}} */ //过滤掉rejected状态,尽可能多的保证页面区域数据渲染 RenderContent(ret.filter((el)=>{ returnel.status!=='rejected'; })); });
二:可选链(Optionalchaining)
可选链可让我们在查询具有多层级的对象时,不再需要进行冗余的各种前置校验。
日常开发中,我们经常会遇到这种查询
varname=user&&user.info&&user.info.name;
又或是这种
varage=user&&user.info&&user.info.getAge&&user.info.getAge();
这是一种丑陋但又不得不做的前置校验,否则很容易命中UncaughtTypeError:Cannotreadproperty...这种错误,这极有可能让你整个应用挂掉。
用了OptionalChaining,上面代码会变成
varname=user?.info?.name;
varage=user?.info?.getAge?.();
可选链中的?表示如果问号左边表达式有值,就会继续查询问号后面的字段。根据上面可以看出,用可选链可以大量简化类似繁琐的前置校验操作,而且更安全。
三:空值合并运算符(NullishcoalescingOperator)
当我们查询某个属性时,经常会遇到,如果没有该属性就会设置一个默认的值。比如下面代码中查询玩家等级。
varlevel=(user.data&&user.data.level)||'暂无等级';
在JS中,空字符串、0等,当进行逻辑操作符判时,会自动转化为false。在上面的代码里,如果玩家等级本身就是0级,变量level就会被赋值暂无等级字符串,这是逻辑错误。
varlevel; if(typeofuser.level==='number'){ level=user.level; }elseif(!user.level){ level='暂无等级'; }else{ level=user.level; }
来看看用空值合并运算符如何处理
//{ //"level":0 //} varlevel=`${user.level}级`??'暂无等级'; //level->'0级'
用空值合并运算在逻辑正确的前提下,代码更加简洁。
空值合并运算符与可选链相结合,可以很轻松处理多级查询并赋予默认值问题。
varlevel=user.data?.level??'暂无等级';
四:dynamic-import
按需import提案几年前就已提出,如今终于能进入ES正式规范。这里个人理解成“按需”更为贴切。现代前端打包资源越来越大,打包成几M的JS资源已成常态,而往往前端应用初始化时根本不需要全量加载逻辑资源,为了首屏渲染速度更快,很多时候都是按需加载,比如懒加载图片等。而这些按需执行逻辑资源都体现在某一个事件回调中去加载。
el.onclick=()=>{ import(`/path/current-logic.js`) .then((module)=>{ module.doSomthing(); }) .catch((err)=>{ //loaderror; }) }
当然,webpack目前已很好的支持了该特性。
五:globalThis
Javascript在不同的环境获取全局对象有不通的方式,node中通过global,web中通过window,self等,有些甚至通过this获取,但通过this是及其危险的,this在js中异常复杂,它严重依赖当前的执行上下文,这些无疑增加了获取全局对象的复杂性。
过去获取全局对象,可通过一个全局函数
vargetGlobal=function(){ if(typeofself!=='undefined'){returnself;} if(typeofwindow!=='undefined'){returnwindow;} if(typeofglobal!=='undefined'){returnglobal;} thrownewError('unabletolocateglobalobject'); }; varglobals=getGlobal(); //https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/globalThis
而globalThis目的就是提供一种标准化方式访问全局对象,有了globalThis后,你可以在任意上下文,任意时刻都能获取到全局对象。
六:BigInt
Js中Number类型只能安全的表示-(2^53-1)至2^53-1范的值,即Number.MIN_SAFE_INTEGER至Number.MAX_SAFE_INTEGER,超出这个范围的整数计算或者表示会丢失精度。
varnum=Number.MAX_SAFE_INTEGER;//->9007199254740991 num=num+1;//->9007199254740992 //再次加+1后无法正常运算 num=num+1;//->9007199254740992 //两个不同的值,却返回了true 9007199254740992===9007199254740993//->true
为解决此问题,ES2020提供一种新的数据类型:BigInt。
使用BigInt有两种方式:
在整数字面量后面加n。
varbigIntNum=9007199254740993n;
使用BigInt函数。
varbigIntNum=BigInt(9007199254740); varanOtherBigIntNum=BigInt('9007199254740993');
通过BigInt,我们可以安全的进行大数整型计算。
varbigNumRet=9007199254740993n+9007199254740993n;//->->18014398509481986n bigNumRet.toString();//->'18014398509481986'
注意:
BigInt是一种新的数据原始(primitive)类型。
typeof9007199254740993n;//->'bigint'
尽可能避免通过调用函数BigInt方式来实例化超大整型。因为参数的字面量实际也是Number类型的一次实例化,超出安全范围的数字,可能会引起精度丢失。
七:String.prototype.matchAll
思考下面代码
varstr='JS 正则 '; varreg=/<\w+>(.*?)<\/\w+>/g; console.log(str.match(reg)); //->["JS ","正则 "]
可以看出返回的数组里包含了父匹配项,但未匹配到子项(group)。移除全局搜索符“g”试试。
varstr='JS 正则 '; //注意这里没有全局搜素标示符“g” varreg=/<\w+>(.*?)<\/\w+>/; console.log(str.match(reg)); //上面会打印出 /* [ "JS ", "JS", index:0, input: "JS 正则 ", groups:undefined ] */
这样可以获取到匹配的父项,包括子项(group),但只能获取到第一个满足的匹配字符。能看出上面无法匹配到
如果获取到全局所有匹配项,包括子项呢?
ES2020提供了一种简易的方式:String.prototype.matchAll,该方法会返回一个迭代器。
varstr='JS 正则 '; varallMatchs=str.matchAll(/<\w+>(.*?)<\/\w+>/g); for(constmatchofallMatchs){ console.log(match); } /* 第一次迭代返回: [ "JS ", "JS", index:0, input:"JS 正则 ", groups:undefined ] 第二次迭代返回: [ "正则 ", "正则", index:15, input:"JS 正则 ", groups:undefined ] */
能看出每次迭代中可获取所有的匹配,以及本次匹配的成功的一些其他元信息。
参考资料
github.com/tc39/proposals/blob/master/finished-proposals.md
prop-tc39.now.sh/
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。