Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nullish coalescing operator '??' #771

Merged
merged 5 commits into from
Jul 18, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 43 additions & 43 deletions 1-js/02-first-steps/12-nullish-coalescing-operator/article.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,57 @@
# Nullish coalescing operator '??'
# 空值合并运算符 '??'

[recent browser="new"]

The nullish coalescing operator `??` provides a short syntax for selecting a first "defined" variable from the list.
空值合并运算符 `??` 提供了一种简短的语法,用来获取列表中第一个“已定义”的变量(译注:即值不是 `null` 或 `undefined` 的变量)。

The result of `a ?? b` is:
- `a` if it's not `null` or `undefined`,
- `b`, otherwise.
`a ?? b` 的结果是:
- `a`,如果 `a` 不是 `null` `undefined`
- `b`,其他情况。

So, `x = a ?? b` is a short equivalent to:
所以,`x = a ?? b` 是下面这个表达式的简写:

```js
x = (a !== null && a !== undefined) ? a : b;
```

Here's a longer example.
下面是一个更长一点的例子。

Imagine, we have a user, and there are variables `firstName`, `lastName` or `nickName` for their first name, last name and the nick name. All of them may be undefined, if the user decided not to enter any value.
假设,我们有一个用户,变量 `firstName``lastName` `nickName` 分别对应用户的名字、姓氏和昵称。如果用户决定不输入任何值,那么这些变量都可能是未定义的。

We'd like to display the user name: one of these three variables, or show "Anonymous" if nothing is set.
我们想要显示用户的名称:显示这三个变量中的一个,如果都没有设置值,则显示 "Anonymous"

Let's use the `??` operator to select the first defined one:
让我们使用 `??` 运算符选择第一个已定义的变量:

```js run
let firstName = null;
let lastName = null;
let nickName = "Supercoder";

// show the first not-null/undefined value
// 显示第一个不是 null/undefined 的值
*!*
alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder
*/!*
```

## Comparison with ||
## 与 || 比较

The OR `||` operator can be used in the same way as `??`. Actually, we can replace `??` with `||` in the code above and get the same result, as it was described in the [previous chapter](info:logical-operators#or-finds-the-first-truthy-value).
或运算符 `||` 可以与 `??` 运算符以同样的方式使用。正如 [上一章](info:logical-operators#or-finds-the-first-truthy-value) 所讲的,我们可以用 `||` 替换上面示例中的 `??`,也可以获得相同的结果。

The important difference is that:
- `||` returns the first *truthy* value.
- `??` returns the first *defined* value.
重要的区别是:
- `||` 返回第一个 **真** 值。
- `??` 返回第一个 **已定义的** 值。

This matters a lot when we'd like to treat `null/undefined` differently from `0`.
当我们想将 `null/undefined` `0` 区别对待时,这个区别至关重要。

For example, consider this:
例如,考虑下面这种情况:

```js
height = height ?? 100;
```

This sets `height` to `100` if it's not defined.
如果 `height` 未定义,则将其赋值为 `100`

Let's compare it with `||`:
让我们将其与 `||` 进行比较:

```js run
let height = 0;
Expand All @@ -60,71 +60,71 @@ alert(height || 100); // 100
alert(height ?? 100); // 0
```

Here, `height || 100` treats zero height as unset, same as `null`, `undefined` or any other falsy value. So the result is `100`.
在这个例子中,`height || 100` 将值为 `0` 的 `height` 视为未设置的(unset),与 `null``undefined` 以及任何其他假(falsy)值同等对待。因此得到的结果是 `100`

The `height ?? 100` returns `100` only if `height` is exactly `null` or `undefined`. So the `alert` shows the height value `0` "as is".
`height ?? 100` 仅当 `height` 确实是 `null` `undefined` 时才返回 `100`。因此,`alert` 按原样显示了 `height` 值 `0`

Which behavior is better depends on a particular use case. When zero height is a valid value, then `??` is preferrable.
哪种行为更好取决于特定的使用场景。当高度 `0` 为有效值时,`??` 运算符更适合。

## Precedence
## 优先级

The precedence of the `??` operator is rather low: `7` in the [MDN table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table).
`??` 运算符的优先级相当低:在 [MDN table](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table) 中为 `7`。

So `??` is evaluated after most other operations, but before `=` and `?`.
因此,`??` 在大多数其他运算之后,但在 `=` `?` 之前进行运算。

If we need to choose a value with `??` in a complex expression, then consider adding parentheses:
如果我们需要在复杂表达式中使用 `??` 进行取值,需要考虑加括号:

```js run
let height = null;
let width = null;

// important: use parentheses
// 重要:使用括号
let area = (height ?? 100) * (width ?? 50);

alert(area); // 5000
```

Otherwise, if we omit parentheses, `*` has the higher precedence than `??` and would run first.
否则,如果我们省略了括号,`*` 的优先级比 `??` 高,会优先执行。

That would work be the same as:
运算过程将等同于下面这个表达式:

```js
// probably not correct
// 可能不正确的
let area = height ?? (100 * width) ?? 50;
```

There's also a related language-level limitation.
这里还有一个相关的语言级别的限制。

**Due to safety reasons, it's forbidden to use `??` together with `&&` and `||` operators.**
**出于安全原因,禁止将 `??` 运算符与 `&&` `||` 运算符一起使用。

The code below triggers a syntax error:
下面的代码会触发一个语法错误:

```js run
let x = 1 && 2 ?? 3; // Syntax error
```

The limitation is surely debatable, but it was added to the language specification with the purpose to avoid programming mistakes, as people start to switch to `??` from `||`.
这个限制无疑是值得商榷的,但是它被添加到语言规范中是为了避免编程错误,因为人们开始使用 `??` 替代 `||`

Use explicit parentheses to work around it:
可以明确地使用括号来解决这个问题:

```js run
*!*
let x = (1 && 2) ?? 3; // Works
let x = (1 && 2) ?? 3; // 起作用
*/!*

alert(x); // 2
```

## Summary
## 总结

- The nullish coalescing operator `??` provides a short way to choose a "defined" value from the list.
- 空值合并运算符 `??` 提供了一种简洁的方式获取列表中“已定义”的值。

It's used to assign default values to variables:
它被用于为变量分配默认值:

```js
// set height=100, if height is null or undefined
// height 的值为 null undefined 时,将 height 的值设置为 100
height = height ?? 100;
```

- The operator `??` has a very low precedence, a bit higher than `?` and `=`.
- It's forbidden to use it with `||` or `&&` without explicit parentheses.
- `??` 运算符的优先级非常低,只略高于 `?` `=`
- 如果没有明确添加括号,不能将其与 `||` `&&` 一起使用。