说起来,[可选链操作符](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/%E5%8F%AF%E9%80%89%E9%93%BE)都加入 `<a href="https://www.babeljs.cn/" class="external-link" rel="nofollow" target="_blank">babel</a>`套餐很久了,但还是没有在实践中大量使用,第一个是对这个特性还是半吊子的理解,第二个是没养成这个习惯。`<br/>`这里将介绍一下可选链操作符是什么,并且列举一下常用的场景,以供下次能在项目实践中更好的使用。

那么这时候你就会得到浏览器给你的一个错误提示

在日常编码中这种操作其实也很常见,我们一般这样编码避免产生这种错误 `obj && obj.name`。但这样属性是一层的还好,但某些极端的场景下,你的数据层级是很深的,比如 `obj.a.b.c.d.name`。这你怎么办,总不能一直一直判断下去吧。在没有可选链式操作符之前,我们通常使用lodash的_.get方法。如图示。但在有了可选链式操作符之后。

上面使用可选链式操作符等价于下方这个表达式| 1 | `let nestedProp = ((obj.a ===<span> </span>``null` `\|\| obj.a=== undefined) ? undefined : (obj.a.b ===<span> </span>``null``) \|\| (obj.a.b === undefined) ? undefined : (obj.a.b [0] ===<span> </span>``null` `\|\| obj.a.b[0] === undefined) ? undefined : obj.a.b[0].name)` |
| --- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

需要注意的是这里如果 **?.** 判断的对象是[nullish](https://developer.mozilla.org/zh-CN/docs/Glossary/Nullish)(要么是**`undefined`**, 要么是** `null`** ) 值的话。表达式就会短路(不在往后执行),返回 `undefined`;并且它跟我们之前经常用的与 或 运算符不一样,因 与 或 运算符是将左侧值转换为真假值来判断是否来执行右侧的,对于假值转换如下条件都会转换为假值* `null`;* `NaN`;* `0`;* 空字符串 (`""`或 `''`或````);* `undefined`.  |
| **常见用法** | ## 1.1. 函数调用比如判断指定实例下是否有对应的方法并调用| 1234567 | `// 以前``if``(_.isFunction(vm.getError)) {``    ``vm.getError()``}``// vm可以是各种实例``// 如果getError存在 则调用 并且getError为undefined也不会出现异常``vm.getError?.()` |
| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

注意: 如果对应getError是个属性而不是一个方法,使用?.仍会抛出一个异常 getError is not a function注意: 如果vm自身是null或undefined,异常仍然会抛出vm is null,所以你如果希望允许其为null或undefined的话 那么你需要这样 vm?.getError?.()## 1.2. 读取对象属性(动态key)当使用方括号来访问属性的时候 也可以使用可选链操作符| 1 | `obj?.[``'name'``]` |
| --- | --------------------------------- |

## 1.3. 读取对象属性| 1 | `obj?.vue?.name` |

| --- | ---------------------- |

## 1.4. 可选链不能用于赋值| 12 | `let obj = {};``obj?.name = 1;<span> </span>``// Uncaught SyntaxError: Invalid left-hand side in assignment` |

| ---- | --------------------------------------------------------------------------------------------------------------------------- |

## 1.5. 数组下标访问| 1 | `arr?.[1]` |

| --- | ---------------- |

`<br/>`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| 实际应用           | 1.基本例子| 1234 | `let myMap =<span> </span>``new` `Map();``myMap.set(``"foo"``, {name:<span> </span>``"baz"``, desc:<span> </span>``"inga"``});` `myMap.get(``"bar"``)?.name;<span> </span>``// undefined` |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

2.短路计算| 1234 | `let yNum = 0;``let xNum =<span> </span>``null``;``let num = xNum?.[yNum++]``console.log(yNum)` |
| ------ | -------------------------------------------------------------------------------------------------------------------------- |

3.连用可选链操作符| 12345678910111213 | `let obj = {``    ``name:``'Vue'``,``    ``age:3,``    ``fun: {``        ``run() {``            ``console.log(``'跑'``)``        ``}``    ``}``}`  `obj?.fun?.run()``obj?.age?.toString()` |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

4.配合空值合并操作符| 123456 | `let obj = {``    ``name:``"Vue"``,``    ``details: {age:3}``}``let city = obj?.details?.city ??<span> </span>``'渐进式框架'``console.log(city)<span> </span>``// '渐进式框架'` |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

5.代替三元运算符| 1234 | `// 之前 obj ? obj.name : '我!默认值!打钱!'`  `// 现在 obj?.name ?? '我!默认值!打钱!'` |
| ------ | ------------------------------------------------------------------------------------------------ |

6.简化正则表达式取值| 12 | `// 之前 let math = "#C0FFEE".match(/#([A-Z0-9]+)/i);let hex = match && match[1]``// 现在 let math = "#C0FFEE".match(/#([A-Z0-9]+)/i)?.[1]` |
| ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |

7.判断某ast节点下是否有指定属性| 12 | `// 之前 if(node.children) { // 逻辑}``// 现在 node?.children` |
| ---- | ------------------------------------------------------------------------ |

需要注意的是 在vue模板中并不支持此写法 因其内并未做相应的处理.相关issue [https://github.com/vuejs/vue/issues/11088#issuecomment-583354390](https://github.com/vuejs/vue/issues/11088#issuecomment-583354390)但vue3中支持了 相关提交 [https://github.com/vuejs/vue-next/commit/8449a9727c942b6049c9e577c7c15b43fdca2867#diff-1cb91d3fc9313f91590cd27606eade47R402](https://github.com/vuejs/vue-next/commit/8449a9727c942b6049c9e577c7c15b43fdca2867#diff-1cb91d3fc9313f91590cd27606eade47R402) |
| 延伸               | Babel基础知识                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
最后修改:2023 年 05 月 08 日
如果觉得我的文章对你有用,请随意赞赏