对象的值藏的太深怎么办? 快来试试可选链操作符 (?.)

1,240 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

在开发的时候经常会遇到这个场景. 有一个存在嵌套结构的对象 obj 需要访问对象深层的属性, 比如 obj.a.b.c 这个时候 如果中间某一层属性不存在, 则在读取下一层属性时, 会抛出 TypeError 的错误. 

想要避免这个错误产生, 我们不得不在每一层加上一个检查, 确保其值既不是 null 也不是 undefined

const obj = {}

// before ES2020 - no checks
obj.a.b  // TypeError: Cannot read property 'b' of undefined
// before ES2020 - incremental nested checks
obj.a && obj.a.b // undefined

这种增量嵌套检查的方法, 在层次深的时候会特别冗长, 既不方便书写, 也不方便阅读

let d = obj.a && obj.a.b && obj.a.b.c && obj.a.b.c.d

可选链操作符

在ES2020迎来了一个新特性: 可选链操作符 ?.  使用可选链操作符, 在访问 obj.a.b 的时候, 不用显式校验 obj.a 的状态再用短路计算拿最终结果

基本用法

我们用可选链操作符重写上面的代码:

const obj = {}

// Optional Chaining
obj.a?.b?.c?.d      // undefined

可选链操作符, 提供了一种方法来简化被连接对象的值的访问, 可以安全的访问对象内部属性, 不必考虑它是否存在.

原理

那么可选运算符的底层是如何实现的呢?  我们可以用 Babel REPL 来查看转换后的js代码

转换前:

before.png

转换后:

after.png

简化以上代码使其更具有可读性:

simple.png

可以看出, 使用 ?. 操作符,  js会在尝试访问 obj.a.b 之前, 先隐式的检查并确定 obj.a 既不是 null 也不是 undefined. 如果是 null 或者 undefined, 表达式会短路计算直接返回 undefined.

其他用法: 

访问数组:

对数组进行下标访问, 可以使用可选链操作符

let item = arr?.[40];

短路计算: 

当在表达式中使用可选链时,如果左操作数是 null 或 undefined,表达式将不会被计算,例如:

let potentiallyNullObj = null;
let x = 0;
let prop = potentiallyNullObj?.[x++];

console.log(x); // x 将不会被递增,依旧输出 0

babel 配置

大部分现代浏览器都支持了可选链操作符?., 为了安全并向后兼容, 还是建议在项目中配置转换插件

// 在 package.json 内 , 安装依赖
{
  "devDependencies": {
    "@babel/core": "^7.12.9",(7.0以下的babel包需删除)
    "@babel/plugin-proposal-optional-chaining": "^7.12.7", (依赖babel 7.0以上)
    "babel-loader": "^8.2.2",
    ...
  }
  ...
}

// 新建文件 ".babelrc.js" (在package.json的同级目录下)
{
  "plugins": [
    "@babel/plugin-proposal-optional-chaining"
  ]
}