JavaScript 中强大的可选链

  • 写在前面
  • 可选链
  • 可选链 de 三种形式
  • 短路:遇到 null/undefined 停止
  • 细节拉满
  • 注意事项
  • 兼容性


写在前面

当你在获取一个对象的属性的时候,你可能需要检测这个属性是否存在,否则会报错;比如:

var obj
console.log(obj.name)

会报错:TypeError: Cannot read property 'name' of undefined

特别是后端接口返回的数据,前端数据一般是你自己定义的,有就是有,没有就是没有;

后端有时候说好的有,结果没有…/(ㄒoㄒ)/~~

javascript 函数可选参数 javascript可选链_可选链


开个玩笑,继续

所以在使用接口返回的数据的时候,要做属性判断,再使用:

if(resp && resp.data) {
  this.tableData = resp.data
}

如果属性嵌套很深,就很难受了 ≧ ﹏ ≦

if (person && person.owner && person.owner.permission) {
  let usecar = person.owner.permission.usecar
}

第三方工具库像 lodash 等,提供了类似这种快捷的判断取值:

// <script src="lodash.js"></script>
_.get(person, 'owner.permission.usecar');

也能够解决对应的问题,但不是本文讨论的问题,重点在下面。

可选链

对于复杂的属性判断,使用 可选链 就很棒了。
它使我们能检查一个对象上面的某属性是否为 null 或者 undefined,如果是,则返回 undefined,而不会报错。

this.tableData = resp?.data

可选链还可以在数组中使用

let moveName = movie.actors?.[0]?.name

可选链 de 三种形式

  • object?.property ;常见的一种
  • object?.[expression] ;用于访问数组项或访问动态属性
  • object?,[arg1, [arg2, ...] ;用于执行对象的一个方法,有时候不知道这个对象的方法是否存在,也可以用可选链来搞
const object = null
object?.method('Some value') // => undefined

短路:遇到 null/undefined 停止

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

const nothing = null;
let index = 0;

nothing?.[index++]; // => undefined
index;              // => 0

细节拉满

对于不存在的属性,可选链返回的是 undefinedundefined 是不太友好的,在代码中会存在问题;我们希望当属性不存在的时候,给一个默认值。

但是如果使用三目运算符,好像有点僵硬

// name不存在的时候,用 - 代替
let moveName = movie.actors?.[0]?.name ? movie.actors?.[0]?.name : '-'

一个新的提议【双问号】 nullish coalescing operator , 处理 undefinednull 的时候,可以给它们默认为特定值。
语法: 变量名 ??

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

noValue ?? 'no value'; // => 'no value'
value   ?? 'no value'; // => 'Hello'

【细节拉满】

// name不存在的时候,用 - 代替
let moveName = movie.actors?.[0]?.name ?? '-'

注意事项

① 避免过度使用

// 连续多次判断同一属性,不好
console.log(foo?.bar)
console.log(foo?.baz)

// 还不如
if(foo) {
  console.log(foo.bar)
  console.log(foo.baz)
}

② 省去赋值判断

// before
if (foo && foo.bar) {
 foo.bar.baz = someValue; 
}

// after
foo?.bar?.baz = someValue

赋值的时候,就不要这样用了;这样运行是会报错的,你可以试一下。

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

// not good
function logMovie(movie) {
  // movie doesn't need optional chaining
  console.log(movie?.title);
}

④有时,你可能有更好的选择

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;
}

// 还不如
function hasPadding({ padding }) {
  const p = {
    top: 0,
    right: 0,
    bottom: 0,
    left: 0,
    ...padding
  };
  return p.top + p.left + p.right + p.bottom !== 0;
}

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

兼容性

在安装了 babel 的情况下,可选链的兼容性还是 OK 的;但是 babel 可能还并不支持 双问号 的语法。(你可以直接尝试一下这个语法,如果不生效,在网上找解决方案)