1、可选的链接操作 '?.'
开发过程中,我们往往会遇到一些复杂的数据结构的数据对象,当我们想用对象中某个层级(可能不存在)的某个属性(可能不存在)时,为了解决js报错的问题,我们往往需要做一些额外的冗错处理。eg:
type IUserProps = { firstName?: string; lastName?: string; age?: number; address?: { number: string; street: string; city: string; zip: string; prop1?: { prop2?: { prop3: { prop4?: { value?: string; }; }; }; }; };};const user:IUserProps = { firstName: 'Joseph', lastName: 'Kuruvilla', age: 38, address: { number: '239', street: 'Ludwig Lane', city: 'Chennai', zip: '600028', prop1: { prop2: { prop3: { prop4: { value: 'sample', }, }, }, }, },};如上面的数据对象,如果我们获取city属性时:
console.log(user.address.city);// error:对象可能为“未定义”。
传统解决方法:
if (user && user.address) { console.lof(user.address.city);//Chennai}如上所示,在访问属性前,你必须检查所访问层级中的属性是否存在,以防止出现“对象可能为“未定义””错误。而随着嵌套级别的增加,你手动检查的属性数量也将随之增加。这意味着一旦我们漏过一项,将会在程序中引发undefined或null对象错误,导致应用出现问题。
可选链接功能出现后
而随着可选链接功能的出现,我们的工作将会变得比较轻松,通过使用可选链接运算符“?.”我们可以访问深度嵌套的对象,而不必检查其是否未定义或null对象。
console.log(user?.address?.city)
console.log(user?.address?.prop1?.prop2?.prop3?.prop4?.value);//sampleES2020通过引入一个 ?. 操作符成功减少了许多代码。
2、空值合并(Nullish Coalescing) '??'
空值合并可以让你检查nullish值而不是falsey值。nullish值是指null或undefined,falsey值是指空字符串,数字0, undefined,null,false,NaN,等值。虽然看起来好像这两个值没什么区别,但实际上差异却很大。
在空值合并之前
比如一个项目,其中需要增加暗夜模式的切换功能。我必须检查输入是否为 true或者false。如果用户没有设置任何值,默认它应该为true。下面是我如何在空值合并出现前实现它的代码。
const darkModePreference1 = trueconst darkModePreference2 = falseconst darkModePreference3 = undefinedconst darkModePreference4 = nullconst getUserDarkModePreference = (darkModePreference) => { if (darkModePreference || darkModePreference === false) { return darkModePreference } return true}getUserDarkModePreference(darkModePreference1)// truegetUserDarkModePreference(darkModePreference2)// falsegetUserDarkModePreference(darkModePreference3)// true
getUserDarkModePreference(darkModePreference4)// true
在空值合并出现后
在使用空值合并后,你所要做的就是使用??操作符。不再需要 if 语句
const darkModePreference1 = trueconst darkModePreference2 = falseconst darkModePreference3 = undefinedconst darkModePreference4 = nullconst getUserDarkModePreference = (darkModePreference) => { return darkModePreference ?? true;}getUserDarkModePreference(darkModePreference1)// truegetUserDarkModePreference(darkModePreference2)// falsegetUserDarkModePreference(darkModePreference3)// truegetUserDarkModePreference(darkModePreference4)// true这里的逻辑是,如果变量darkModePreference包含一个空值,那么就把true赋给它,使用这个特性的代码简单易懂。
3、动态导入
此功能将帮助你的应用更高效地运行。动态导入允许你实时地在应用中以模块的形式按需导入js文件。在ES2020之前,无论你是否使用了该模块,都应该提前导入它。
例如,假设我们需要添加一个功能来下载一个pdf格式的文件。
让我们看看如何在动态导入之前和之后如何实现这一点有什么异同。
动态导入之前
在实际项目中,下载pdf的功能不会被所有的网站访客使用。但是,不管我们的访问者是否使用它,它都需要导入。这意味着这个pdf模块也会在页面加载时被载入。
import { exportAsPdf } from './export-as-pdf.js'const exportPdfButton = document.querySelector('.exportPdfBtn');exportPdfButton.addEventListener('click', exportAsPdf);这种开销可以通过使用延迟加载模块来减少。可以通过代码分离(code-splitting)来实现,代码分离已经可以通过webpack或其他模块打包工具来实现。
但是在ES2020中我们以原生的方式来实现这个功能,不再需要模块打包工具等其他方式减少开销了。
动态导入之后
const exportPdfButton = document.querySelector('.exportPdfBtn');exportPdfButton.addEventListener('click', () => { import('./export-as-pdf.js').then(module => { module.exportAsPdf() }) .catch(err => { // handle the error if the module fails to load })})如上面的代码中所看到的那样,现在可以按需加载所使用的模块,从而减少应用的开销和页面加载时间。
4、Promise.allSettled
如果你有这样一个场景,一旦所有的promise都完成了,就必须执行一个任务,你会使用Promise.all()方法。这个方法有一个缺点。当任何一个promise被拒绝时,都会抛出一个错误。这意味着你的代码不会等到你所有的promise都完成。
这可能不是你想要的。如果你的需求是不关心它们的结果,只需将它们全部运行,你可以使用新的Promise.allSettled()方法。这种方法只有在你所有的promise都执行完成之后才会调用。
使用 promise.all
const PromiseArray = [ Promise.resolve(100), Promise.reject(null), Promise.resolve("Data release"), Promise.reject(new Error('Something went wrong'))];Promise.all(PromiseArray).then(data => console.log('all resolved! here are the resolve values:', data)).catch(err => console.log('got rejected! reason:', err))//got rejected! reason: null如上面的代码,当一个promise失败时,会引发错误。
使用 promise.allSettled
const PromiseArray = [ Promise.resolve(100), Promise.reject(null), Promise.resolve("Data release"), Promise.reject(new Error('Something went wrong'))];Promise.allSettled(PromiseArray).then(res =>{console.log(res);}).catch(err => console.log(err));//[//{status: "fulfilled", value: 100},//{status: "rejected", reason: null},//{status: "fulfilled", value: "Data release"},//{status: "rejected", reason: Error: Something went wrong ...}//]即使有些promise被拒绝,Promise.allSettled仍然会在所有promise执行完成后为你返回结果
5、其它
BigInt
允许你使用比JavaScript中允许的最大值大的数字。这个数字是pow(2,53)-1。不过这并不是向后兼容的,因为传统的浮点数标准(IEEE 754)不支持这种大小的数字。
String.matchAll
matchAll() 是一个和正则表达式相关的方法。它返回一个包含所有匹配正则表达式的结果及分组捕获组的迭代器。这个方法添加到了 String 原型里。
globalThis
globalThis是对全局对象的引用,与环境无关。在浏览器中,全局对象是window对象。在Node环境中,全局对象是global对象,在web worker中是self。
总结
个人觉得在开发过程中,1、2、3、4条特性对我们有很大的帮助,其中的场景我们会经常遇到,这些特性可以减少我们开销。