JS可选链的好处

做者:Dmitri Pavlutinjavascript

译者:前端小智html

来源:dmitripavlutin前端


阿里云最近在作活动,低至2折,有兴趣能够看看promotion.aliyun.com/ntms/yunpar…java


为了保证的可读性,本文采用意译而非直译。git

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

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

来看看这是又是什么骚操做。数组

这个礼拜《大迁世界》有抽奖活动,奖品:专栏 《左耳听风》 x3, 技术书 x5,欢迎关注回复:抽奖安全

问题

因为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 可能不存在。

function getDirector(movie) {
  if (movie.director != null) {
    return movie.director.name;
  }
}

getDirector(movieSmall); // => undefined
getDirector(movieFull);  // => '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); // => undefined
getDirector(movieFull);  // => '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); // => undefined
getLeadingActor(movieFull);  // => 'Harrison Ford'
复制代码

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

使用可选连接,一样代码也简洁了很了,以下:

function getLeadingActor(movie) {
  return movie.actors?.[0]?.name;
}

getLeadingActor(movieSmall); // => undefined
getLeadingActor(movieFull);  // => 'Harrison Ford'
复制代码

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

3.双问号操做符

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

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

const noValue = undefined;
const value = 'Hello';

noValue ?? 'Nothing'; // => 'Nothing'
value   ?? 'Nothing'; // => 'Hello'
复制代码

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

function getLeadingActor(movie) {
  return movie.actors?.[0]?.name ?? 'Unknown actor';
}

getLeadingActor(movieSmall); // => 'Unknown actor'
getLeadingActor(movieFull);  // => 'Harrison Ford'
复制代码

4. 可选链的三种形式

我们可使用如下3种形式的可选链。

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

const object = null;
object?.property; // => undefined
复制代码

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

// 其一
const object = null;
const name = 'property';
object?.[name]; // => undefined
// 其二
const array = null;
array?.[0]; // => undefined
复制代码

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

const object = null;
object?.method('Some value'); // => undefined
复制代码

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

const value = object.maybeUndefinedProp?.maybeNull()?.[propName];
复制代码

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

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

看看例子:

const nothing = null;
let index = 0;

nothing?.[index++]; // => undefined
index;              // => 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' });        // => false
hasPadding({ padding: { left: 0 } });  // => false
hasPadding({ padding: { right: 10 }}); // => 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' });        // => false
hasPadding({ padding: { left: 0 } });  // => false
hasPadding({ padding: { right: 10 }}); // => true
复制代码

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

代码部署后可能存在的BUG无法实时知道,过后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给你们推荐一个好用的BUG监控工具 Fundebug

原文:dmitripavlutin.com/javascript-…

交流(欢迎加入群,群工做日都会发红包,互动讨论技术)

干货系列文章汇总以下,以为不错点个Star,欢迎 加群 互相学习。

github.com/qq449245884…

我是小智,公众号「大迁世界」做者,对前端技术保持学习爱好者。我会常常分享本身所学所看的干货,在进阶的路上,共勉!

关注公众号,后台回复福利,便可看到福利,你懂的。

相关文章
相关标签/搜索