ES2020 已定稿,真实场景案例分析
近年来,JavaScript的发展非常迅速。尤其是在2015年ES6发布之后,情况变得更好。
现在许多新的特性被提议包括在ES2020版本中。好消息是这些已经已经敲定。现在,我们获得了最终定稿的功能清单,它们将在被批准发布之后出现在备受期待的ES2020中。其中一些功能使我非常兴奋,因为在它们存在之前编写代码时遇到将会遇到很多麻烦。让我们看看它们是什么吧!
可选链操作符(OptionalChainingOperator)
对我个人来说,这是ES2020最令人兴奋的特点之一。我已经编写了很多程序,这些程序将会从这个新特性中获益匪浅。
可选链操作符允许您安全地访问对象的深嵌套属性,而不必检查每个属性是否存在。让我们看看这个特性对我们有什么帮助。
拥有可选链操作符之前
constuser={
firstName:"Joseph",
lastName:"Kuruvilla",
age:38,
address:{
number:"239",
street:"LudwigLane",
city:"Chennai",
zip:"600028",
prop1:{
prop2:{
prop3:{
prop4:{
value:"sample",
},
},
},
},
},
};
if(user&&user.address){
console.log(user.address.zip);
//600028
}
if(
user&&
user.address&&
user.address.prop1&&
user.address.prop1.prop2&&
user.address.prop1.prop2.prop3&&
user.address.prop1.prop2.prop3.prop4
){
console.log(user.address.prop1.prop2.prop3.prop4.value);
//sample
}
//Accessingunexistingproperty
console.log(user.address.prop102.po);
//Error
正如您在上面看到的,您必须检查每个级别中是否存在该属性,以避免出现无法读取未定义属性“po”的错误。随着嵌套级别的增加,手动检查的属性数量也会增加。这意味着我们必须检查每个级别,以确保它不会在遇到未定义或空对象时崩溃。
拥有可选链式操作符之后
随着可选链式操作符(OptionalChaining)的引入,我们前端的工作变得容易多了。通过简单地使用可选链式操作符?.我们可以访问深嵌套的对象,而不必检查未定义或空对象。
让我们看看它是如何运作的。
constuser={
firstName:"Joseph",
lastName:"Kuruvilla",
age:38,
address:{
number:"239",
street:"LudwigLane",
city:"Chennai",
zip:"600028",
prop1:{
prop2:{
prop3:{
prop4:{
value:"sample",
},
},
},
},
},
};
console.log(user?.address?.zip);
//600028
console.log(user?.address?.prop1?.prop2?.prop3?.prop4?.value);
//sample
//Accessingunexistingproperty
console.log(user?.address?.prop102?.po);
//undefined
太神奇了!ES2020成功地通过引入一个单独的代码操作符?.来减少了如此多的代码行数!
空值合并操作符(Nullishcoalescingoperator)
这是另一个令我兴奋的功能,当我第一次在proposalstage,了解到的时候,我由衷的喜欢这个特性,因为我已经历了编写单独的函数来手动检查这个特性的麻烦。
空值合并操作符允许您检查nullish值而不是 falsey值。Nullish值是指 null或undefined的值。而falsey值是诸如空字符串、数字0、 undefined、 null、 false、 NaN等等的值。这对你来说可能听起来没什么不同,但是在现实中,这意味着很多。
让我们看看这是怎么回事。
在有空值合并操作符之前
我最近做了一个项目,我需要允许黑暗模式(DarkMode)切换功能。我必须检查输入是true还是 false。如果用户没有设置任何值,则默认为 true。下面就是我如何在有空值合并操作符之前实现它的:
constdarkModePreference1=true;
constdarkModePreference2=false;
constdarkModePreference3=undefined;
constdarkModePreference4=null;
constgetUserDarkModePreference=(darkModePreference)=>{
if(darkModePreference||darkModePreference===false){
returndarkModePreference;
}
returntrue;
};
getUserDarkModePreference(darkModePreference1);
//true
getUserDarkModePreference(darkModePreference2);
//false
getUserDarkModePreference(darkModePreference3);
//true
getUserDarkModePreference(darkModePreference4);
//true
在有空值合并操作符之后
在有空值合并操作符之后,您所要做的就是使用??操作符。不需要 if语句:
constdarkModePreference1=true;
constdarkModePreference2=false;
constdarkModePreference3=undefined;
constdarkModePreference4=null;
constgetUserDarkModePreference=(darkModePreference)=>{
returndarkModePreference??true;
};
getUserDarkModePreference(darkModePreference1);
//true
getUserDarkModePreference(darkModePreference2);
//false
getUserDarkModePreference(darkModePreference3);
//true
getUserDarkModePreference(darkModePreference4);
//true
这里基本上发生的情况是,如果变量darkModePreference包含一个nullish值,那么将值true赋给它。简单,简短,易于理解。
动态import(DynamicImports)
这个特性将帮助您的应用程序更加高效的执行,动态import允许您将JS文件作为原生应用用程序中的模块动态导入。在ES2020之前,不管是否使用模块,都应该导入模块。
例如,假设我们需要添加一个功能来下载pdf格式的文件。
让我们看看如何在动态import之前和之后实现这一点。
在动态import 之前
实际上,不会所有的页面访问者使用下载pdf的选项。但是,无论我们的访客是否使用它,它仍然需要被导入。这意味着这个pdf模块也可以在页面加载期间被下载。
import{exportAsPdf}from"./export-as-pdf.js";
constexportPdfButton=document.querySelector(".exportPdfBtn");
exportPdfButton.addEventListener("click",exportAsPdf);
这种开销可以通过使用延迟加载模块(lazyloadedmodules)来减少。可以通过称为代码分割(code-splitting)的方法来实现,这在Webpack或其他模块打包工具已经可以使用了。但是对于ES2020,我们可以直接使用它了,而不需要模块打包工具,如Webpack。
在动态导入(动态import)之后
constexportPdfButton=document.querySelector('.exportPdfBtn');
exportPdfButton.addEventListener('click',()=>{
import('./export-as-pdf.js')
.then(module=>{
module.exportAsPdf()
})
.catch(err=>{
//handletheerrorifthemodulefailstoload
})
})
正如您在上面的代码中看到的,现在只有在需要模块时才延迟加载模块。从而减少开销和页面加载时间。
Promise.allSettled
如果你有一个场景,在所有Promise都完成之后必须执行一个任务,那么你可能使用Promise.all()方法。但是这个方法有一个缺点。当你的任何一个Promise被Rejected时,Promise方法就会抛出一个错误。这意味着您的代码不会等到所有的Promise都完成。
这可能不是你想要的。如果你想要这样的东西:“我不在乎他们的结果。只需全部运行”,那么你可以使用新的Promise.allSettled()方法。这种方法只有在你的所有Promise都 settledーー要么 Resolved,要么 Rejectedーー时才会 Resolved。
在拥有Promise.allSettled之前
constPromiseArray=[
Promise.resolve(100),
Promise.reject(null),
Promise.resolve("Datarelease"),
Promise.reject(newError("Somethingwentwrong")),
];
Promise.all(PromiseArray)
.then((data)=>
console.log("allresolved!herearetheresolvevalues:",data)
)
.catch((err)=>console.log("gotrejected!reason:",err));
//gotrejected!reason:null
如上所述,当其中一个Promise被rejected时,Promise就会抛出错误。
在拥有Promise.allSettled之后
constPromiseArray=[
Promise.resolve(100),
Promise.reject(null),
Promise.resolve("Datarelease"),
Promise.reject(newError("Somethingwentwrong")),
];
Promise.allSettled(PromiseArray)
.then((res)=>{
console.log(res);
})
.catch((err)=>console.log(err));
//[
//{status:"fulfilled",value:100},
//{status:"rejected",reason:null},
//{status:"fulfilled",value:"Datarelease"},
//{status:"rejected",reason:Error:Somethingwentwrong...}
//]
尽管有些Promise被rejected了,Promise.allSettled返回了所有的Promise的结果。
globalThis
globalThis包含对全局对象的引用,与环境无关。在浏览器中,全局对象是 window对象。在Node环境中,全局对象是 global或者Webworkers中的 self。
在拥有globalThis之前
我们在工作中会有需要编写一份同时运行在Node和浏览器中的通用代码,当我们要取得全局对象时,通常需要做很多工作和逻辑判断:
beforeGlobalThis=(typeofwindow!=="undefined" ?window :(typeofprocess==='object'&& typeofrequire==='function'&& typeofglobal==='object') ?global :this); beforeGlobalThis.tuture='小若燕雀,亦可一展宏图';
在拥有globalThis之后
我们可以直接使用globalThis去引用全局对象,而不用去担心环境的问题:
globalThis.tuture='小若燕雀,亦可一展宏图';
上面的代码在浏览器或者Node环境中都是通用的,你可以放心使用!
BigInt
允许您使用大于Javascript中允许的最大值的数字。这个数字是pow(2,53)-1。尽管这不能向后兼容,因为传统的数字系统(IEEE754)不能支持这种大小的数字。
String.matchall
matchAll()是一个与正则表达式相关的方法。此方法返回与正则表达式匹配的字符串的所有结果的迭代器,包括捕获组。这个方法已经被添加到String原型中。
参考资源
ECMA
InfoQ
ArticlebyTylerHawkins
总结
到此这篇关于ES2020已定稿,真实场景案例分析的文章就介绍到这了,更多相关ES2020已定稿内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!