1. 首页

JavaScript可选链的好处之缺点

JS的一些特性极大地改变了咱们的编码方式。从ES6年开始,对咱们代码影响最大的特性的解 、箭头函数、类和模块系统。

到2019年8月,一个新的可选链提案已经进入第三阶段,这是一个很好的改进。可选链接改变了从深层对象结构访问属性的方式。

来看看这是又是什么骚操作。

问题

由于JS的动态特性,对象可以具有多层不同的嵌套对象结构。

通常,当咱们处理以下这些对象时:

  • 获取远程JSON数据
  • 使用配置对象
  • 有可选属性

虽然JS为对象支持不同层次数据结构,但是在访问此类对象的属性时,复杂性也随着增加。

bigObject可以在运行时拥有不同的属性集


// 嵌套版本 const bigObject = { // ... prop1: { //... prop2: { // ... value: 'Some value' } } }; // 简单版本 const bigObject = { // ... prop1: { // Nothing here } };

因此,必须手动检查属性是否存在


if (bigObject && bigObject.prop1 != null && bigObject.prop1.prop2 != null) { let result = bigObject.prop1.prop2.value; }

这样写太过冗长了,最好避免写它。

咱们来看看可选链如何解决这个问题,以减少冗余的代码。

2. 易于深入访问属性

设计一个保存电影信息的对象。 该对象包含必填title属性,以及可选的directoractors

movieSmall对象仅包含title,而movieFull包含完整的属性集:


const movieSmall = { title: 'Heat' }; const movieFull = { title: 'Blade Runner', director: { name: 'Ridley Scott' }, actors: [{ name: 'Harrison Ford' }, { name: 'Rutger Hauer' }] };

写一个获取director的函数。 请记住,director 可能不存在。

JS中文网 – 前端进阶资源教程 https://www.javascriptc.com/
一个致力于帮助开发者用代码改变世界为使命的平台,每天都可以在这里找到技术世界的头条内容


function getDirector(movie) { if (movie.director != null) { return movie.director.name; } } getDirector(movieSmall); // Js中文网 => undefined getDirector(movieFull); // Js中文网 => 'Ridley Scott'

if(movie.director){...}条件用于验证是否定义了director属性。 如果没有这个预防措施,在访问movieSmall对象的director时,JS会抛出TypeError: Cannot read property 'name' of undefined

这种场景最适合使用可选链的功能了,如下所示,代码将简洁很多。


function getDirector(movie) { return movie.director?.name; } getDirector(movieSmall); // Js中文网 => undefined getDirector(movieFull); // Js中文网 => 'Ridley Scott'

在movie.director?.name表达式中可以找到?.可选的链接操作符。

movieSmall中,没有director属性。 因此,movie.director?.name的的结果为undefined。 可选链运算符可防止抛出 TypeError: Cannot read property 'name' of undefined

简单地说,代码片段:


let name = movie.director?.name;

等价于


let name; if (movie.director != null) { name = movie.director.name; }

?.通过减少两行代码简化getDirector()函数,这就是为什么我喜欢可选链的原因。

2.1 数组项

可选的链功能可以做得更多。可以自由地在同一个表达式中使用多个可选的链接操作符,甚至可以使用它安全地访问数组项。

下一个任务是编写一个函数,返回电影的actors中的name

movie对象中,actors数组可以是空的,甚至是缺失的,因此必须添加额外的条件来判空。


function getLeadingActor(movie) { if (movie.actors && movie.actors.length > 0) { return movie.actors[0].name; } } getLeadingActor(movieSmall); // Js中文网 => undefined getLeadingActor(movieFull); // Js中文网 => 'Harrison Ford'

if (movie.actors && movies.actors.length > 0) {...}条件主要判断movie包含actors属性,并且此属性至少有一个actor

使用可选链接,同样代码也简洁了很了,如下:


function getLeadingActor(movie) { return movie.actors?.[0]?.name; } getLeadingActor(movieSmall); // Js中文网 => undefined getLeadingActor(movieFull); // Js中文网 => 'Harrison Ford'

actors?. 确保actors属性存在, [0]?.确保列表中存在第一个actor

3.双问号操作符

一个名为nullish coalescing operator的新提议? 处理undefinednull,将它们默认为特定值。

表达式变量?? 如果变量undefined或为null,则默认值为指定的值。


const noValue = undefined; const value = 'Hello'; noValue ?? 'Nothing'; // Js中文网 => 'Nothing' value ?? 'Nothing'; // Js中文网 => 'Hello'

接着使用??来优化一下 getLeading()函数,当movie对象中没有actor时返回“Unknown actor


function getLeadingActor(movie) { return movie.actors?.[0]?.name ?? 'Unknown actor'; } getLeadingActor(movieSmall); // Js中文网 => 'Unknown actor' getLeadingActor(movieFull); // Js中文网 => 'Harrison Ford'

4. 可选链的三种形式

咱们可以使用以下3种形式的可选链。

第一种: object?.property 用于访问静态属性:


const object = null; object?.property; // Js中文网 => undefined

第二种:object?.[expression] 用于访问动态属性或数组项:


// 其一 const object = null; const name = 'property'; object?.[name]; // Js中文网 => undefined // 其二 const array = null; array?.[0]; // Js中文网 => undefined

第三种:object?.([arg1, [arg2, ...]]) 执行一个对象方法


const object = null; object?.method('Some value'); // Js中文网 => undefined

将这三种组合起来创建一个可选链:


const value = object.maybeUndefinedProp?.maybeNull()?.[propName];

5.短路:遇到 null/undefined 停止

可选链接运算符的有趣之处在于,只要在左侧leftHandSide?.rightHandSide遇到无效值,右侧访问就会停止,这称为短路。

看看例子:


const nothing = null; let index = 0; nothing?.[index++]; // Js中文网 => undefined index; // Js中文网 => 0

6. 何时使用可选链

不要急于使用可选的链操作符来访问任何类型的属性:这会导致错误的使用。

6.1访问潜在无效的属性

?.一般使用在可能为空的属性:maybeNullish?.prop。在确定属性不为空的情况下,使用属性访问器:.property或[propExpression]


// 好 function logMovie(movie) { console.log(movie.director?.name); console.log(movie.title); } // 不好 function logMovie(movie) { // director needs optional chaining console.log(movie.director.name); // movie doesn't need optional chaining console.log(movie?.title); }

6.2 通常有更好的选择

以下函数hasPadding()接收可选padding属性的样式对象。 padding具有lefttoprightbottom可选属性。

尝试使用可选的链操作符:


function hasPadding({ padding }) { const top = padding?.top ?? 0; const right = padding?.right ?? 0; const bottom = padding?.bottom ?? 0; const left = padding?.left ?? 0; return left + top + right + bottom !== 0; } hasPadding({ color: 'black' }); // Js中文网 => false hasPadding({ padding: { left: 0 } }); // Js中文网 => false hasPadding({ padding: { right: 10 }}); // Js中文网 => true

虽然函数正确地确定了元素是否有padding,但是对于每个属性使用可选的链有点过于麻烦了。

更好的方法是使用对象扩展操作符将padding对象默认为零值


function hasPadding({ padding }) { const p = { top: 0, right: 0, bottom: 0, left: 0, ...padding }; return p.top + p.left + p.right + p.bottom !== 0; } hasPadding({ color: 'black' }); // Js中文网 => false hasPadding({ padding: { left: 0 } }); // Js中文网 => false hasPadding({ padding: { right: 10 }}); // Js中文网 => true

这个就比可选链来的更简洁。

*

码农进阶题库,每天一道面试题 or Js小知识 https://www.javascriptc.com/interview-tips/

作者:前端小智
链接:https://segmentfault.com/a/1190000020173404

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

本文著作权归作者所有,如若转载,请注明出处

转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com

标题:JavaScript可选链的好处之缺点

链接:https://www.javascriptc.com/3525.html

« JavaScript中函数式编程基本原理简介
JavaScript它如何运行: Shadow DOM 的内部结构+如何编写独立的组件!»
Flutter 中文教程资源

相关推荐

QR code