当前位置: 首页 > 科技观察

为什么我喜欢JavaScript可选链

时间:2023-03-13 12:06:09 科技观察

许多JavaScript功能极大地改变了您的编码方式。自ES2015及更高版本以来对我的代码产生重大影响的功能是解构、箭头函数、类和模块系统。截至2019年8月,一项新提案,即可选链接,进入了第3阶段,这将是一个不错的改进。可选链接改变了从深层对象结构访问属性的方式。让我们看看可选链接如何通过在访问可能缺失的属性时删除样板条件和变量来简化代码。1.问题由于JavaScript的动态特性,一个对象可以有非常不同的对象嵌套结构。通常,您可以在以下情况下处理此类对象:获取远程JSON数据使用具有可选属性的配置对象这就增加了复杂性。bigObject在运行时可以有不同的属性集://OneversionofbigObjectconstbigObject={//...prop1:{//...prop2:{//...value:'Somevalue'}}};//OtherversionofbigObjectconstbigObject={///...prop1:{//这里什么都没有}};所以你必须手动检查属性是否存在://Laterif(bigObject&&bigObject.prop1!=null&&bigObject.prop1.prop2!=null){letresult=bigObject.prop1.prop2.value;}这个最好不要写,因为它包含太多样板代码。.让我们看看可选链如何解决这个问题,减少样板条件。2.轻松深入访问属性让我们设计一个保存电影信息的对象。该对象包含必需的属性标题,以及可选的导演和演员。movieSmall对象仅包含标题,而movieFull包含完整的属性集:constmovieSmall={title:'Heat'};constmovieFull={title:'BladeRunner',director:{name:'RidleyScott'},actors:[{名称:'HarrisonFord'},{名称:'RutgerHauer'}]};让我们编写一个获取导演姓名的函数。请注意,director属性可能会丢失:functiongetDirector(movie){if(movie.director!=null){returnmovie.director.name;}}getDirector(movieSmall);//=>undefinedgetDirector(movieFull);//=>'RidleyScott'if(movie.director){...}条件用于验证导演属性是否已定义。如果没有这种预防措施,JavaScript会在访问movieSmall对象的导演时引发错误TypeError:Cannotreadproperty'name'ofundefined。这是使用可选链接功能并删除movie.director存在性验证的正确位置。新版本的getDirector()看起来要短得多:在director?.name表达式中,您可以找到?.:可选的链接运算符。对于movieSmall,缺少属性director。结果movie.director?.name评估为未定义。可选的链接运算符可防止引发TypeError:Cannotreadproperty'name'ofundefined错误。相反,可以使用movieFull属性控制器。movie.director?.name默认情况下评估为“RidleyScott”。简而言之,代码片段:letname=movie.director?.name;等同于:letname;if(movie.director!=null){name=movie.director.name;}?。通过减少两行代码进行简化添加了getDirector()函数。这就是为什么我喜欢可选链接。2.1数组项的可选链接可以做得更多。您可以在同一表达式中自由使用多个可选的链接运算符。您甚至可以使用它来安全地访问数组项!下一个任务是编写一个函数,返回电影中主角的名字。在movie对象中,actors数组可以为空甚至缺失,因此您必须添加另一个条件:functiongetLeadingActor(movie){if(movie.actors&&movie.actors.length>0){returnmovie.actors[0].name;}}getLeadingActor(movieSmall);//=>undefinedgetLeadingActor(movieFull);//=>'HarrisonFord'如果你需要if(movie.actors&&movies.actors.length>0){...},你必须保证电影包含演员属性,并且该属性中至少有一个演员。使用可选链接,这个任务很容易解决:functiongetLeadingActor(movie){returnmovie.actors?.[0]?.name;}getLeadingActor(movieSmall);//=>undefinedgetLeadingActor(movieFull);//=>'HarrisonFord'演员?确保演员属性存在。[0]?.确保第一个参与者存在于列表中。这个真是好东西。3.默认为Nullish合并一项名为nullish合并运算符的新提案处理undefined或null,将其默认为特定值。如果变量未定义或为空,表达式变量??defaultValue的计算结果为defaultValue。否则,表达式的计算结果为变量值。constnoValue=undefined;constvalue='Hello';noValue??'Nothing';//=>'Nothing'值??'Nothing';//=>'Hello'通过设置链计算为undefined时的默认值零,Nullish合并改进了可选链接。例如,如果电影对象中没有演员,让我们更改getLeading()函数以返回“未知演员”:functiongetLeadingActor(movie){returnmovie.actors?.[0]?.name??'Unknownact??or';}getLeadingActor(movieSmall);//=>'Unknownact??or'getLeadingActor(movieFull);//=>'HarrisonFord'4.可选链的三种形式您可以使用以下三种形式的可选链。object.property第一种形式用于访问静态属性:constobject=null;object?.property;//=>undefined第二种形式object?.[expression]用于访问动态属性或数组项:constobject=null;constname='property';object?.[name];//=>undefinedconstarray=null;array?.[0];//=>undefined最后是第三种形式object?.([arg1,[arg2,...]])执行一个对象方法:constobject=null;object?.method('Somevalue');//=>undefined如果需要,可以组合这些形式来创建长可选链:constvalue=object.maybeUndefinedProp?.maybeNull()?.[propName];5.短路:在null/undefined处停止可选链接运算符的有趣之处在于,一旦在其左侧leftHandSide?.rightHandSide遇到null,将停止对右访问器的求值。这称为短路。看个例子:constnothing=null;letindex=0;nothing?.[index++];//=>undefinedindex;//=>0nothing留空值,所以可选链立即求值为undefined,跳过右边的求值的访问者。因为索引的值没有增加。6.何时使用可选链抵制使用可选链运算符来访问任何类型的属性的冲动:这会导致不正确的使用。下一节将解释何时正确使用它。6.1可能无效的访问属性必须使用?。仅围绕可能为空的属性:maybeNullish?.prop。在其他情况下,使用旧式属性访问器:.property或[propExpression]。调用电影对象。查看表达式movie.director?.name,因为director可以未定义,所以在director属性周围使用可选的链接运算符是正确的。相反,使用?。访问电影标题movie?.title没有任何意义。电影对象不会为空。//GoodfunctionlogMovie(movie){console.log(movie.director?.name);console.log(movie.title);}//BadfunctionlogMovie(movie){//directorneedsoptionalchainingconsole.log(movie.director.name);//moviedoesn'tneedoptionalchainingconsole.log(movie?.title);}6.2通常有更好的选择以下函数hasPadding()接受具有可选填充属性的样式对象。padding有可选属性left,top,right,bottom。尝试可选的链接运算符:functionhasPadding({padding}){consttop=padding?.top??0;constright=padding?.right??0;constbottom=padding?.bottom??0;constleft=padding?。left??0;returnleft+top+right+bottom!==0;}hasPadding({color:'black'});//=>falsehasPadding({padding:{left:0}});//=>falsehasPadding({padding:{right:10}});//=>true虽然该函数正确地确定元素是否具有填充,但没有必要为每个属性使用可选链接。更好的方法是使用对象扩展运算符将填充对象默认为零值:functionhasPadding({padding}){constp={top:0,right:0,bottom:0,left:0,...padding};returnp.top+p.left+p.right+p.bottom!==0;}hasPadding({color:'black'});//=>falsehasPadding({padding:{left:0}});//=>falsehasPadding({padding:{right:10}});//=>true我觉得这个版本的hasPadding()可读性更好。7、我为什么喜欢它?我喜欢可选的链接运算符,因为它允许轻松访问嵌套对象的属性。它可以防止编写样板代码来验证访问器链中每个属性访问器的空值。当可选链接与null合并运算符结合使用时可以获得更好的结果,从而更容易处理默认值。