# 12 可选链与空值合并

## 可选链运算符

可选链运算符 `?.` 允许读取位于连接对象链深处的属性的值，而不必明确验证链中的每个引用是否有效。`?.` 运算符的功能类似于 `.` 链式运算符，不同之处在于，在引用为空 `nullish (null 或者 undefined)` 的情况下不会引起错误，该表达式短路返回值是 `undefined`。与函数调用一起使用时，如果给定的函数不存在，则返回 `undefined`。

语法：

```javascript
obj.val?.prop
obj.val?.[expr]
obj.func?.(args)
```

栗子：

```javascript
const nestedProp = obj.first?.second

// 等价于
const temp = obj.first
const nestedProp = temp === null || temp === undefined ? undefined : temp.second
```

实战：

```javascript
// 可选链和表达式
const nestedProp = obj?.['prop' + 'Name']

// 可选链不能用于赋值
const object = {}
object?.property = 1 // Uncaught SyntaxError: Invalid left-hand side in assignment

// 可选链访问数组元素
const arrayItem = arr?.[42]
```

## 空值合并运算符

空值合并运算符 `??` 是一个逻辑运算符，当左侧的操作数为 `null` 或者 `undefined` 时，返回其右侧操作数，否则返回左侧操作数。

与逻辑或运算符 `||` 不同，逻辑或运算符会在左侧操作数为假值时返回右侧操作数。也就是说，如果使用 `||` 来为某些变量设置默认值，可能会遇到意料之外的行为。比如为假值（例如 `''` 或 `0`）时。

```javascript
const qty = 0 ?? 42 // 0
const message = '' ?? 'hi!' // ''

const qty = 0 || 42 // 42
const message = '' || 'hi!' // 'hi!'
```

**空值合并运算符可以避免这种陷阱，其只在第一个操作数为 `null` 或 `undefined` 时（而不是其它假值）返回第二个操作数。**

短路：与 `OR` 和 `AND` 逻辑运算符相似，当左表达式不为 `null` 或 `undefined` 时，不会对右表达式进行求值。

```javascript
function A() {
  return undefined
}
function B() {
  return false
}
function C() {
  return 'foo'
}

A() ?? C() // A 和 C 都被执行

B() ?? C() // 只执行 B
```

不能与 `AND` 或 `OR` 运算符共用，因为空值合并运算符和其他逻辑运算符之间的运算优先级/运算顺序是未定义的，这种情况下会抛出 `SyntaxError`。

```javascript
null || undefined ?? 'foo' // 抛出 SyntaxError
true || undefined ?? 'foo' // 抛出 SyntaxError

// 但是如果使用括号来显式表明运算优先级，是没有问题的
(null || undefined ) ?? 'foo' // 返回 'foo'
```

需要注意的一点是，**空值合并运算符和 JavaScript 中的默认参数是有一点不一样的。因为默认参数只有在 `undefined` 的情况下才会进行默认值赋值操作，而参数为 `null` 时不会默认赋值。**

可选链运算符和空值合并运算符可以放在一起操作，确保值不存在的时候，有一个兜底的默认值可以给程序使用：

```javascript
const x = foo?.bar?.() ?? 'default'
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://chanshiyu.gitbook.io/blog/qian-duan/javascript/12-ke-xuan-lian-yu-kong-zhi-he-bing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
