Skip to content

Commit e354cc1

Browse files
committed
Translate 1.2.12. Nullish coalescing operator
1 parent 74ee137 commit e354cc1

File tree

35 files changed

+168
-0
lines changed

35 files changed

+168
-0
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# Оператор объединения с null '??'
2+
3+
[recent browser="new"]
4+
5+
В этой статье мы считаем выражение "определённым", если его значение отличается от `null` или `undefined`.
6+
7+
Оператор объединения с null представляет собой два вопросительных знака `??`.
8+
9+
Результат выражения `a ?? b` будет следующим:
10+
- `a`, если `a` — определённое значение,
11+
- `b`, если значение `a` не определено.
12+
13+
То есть оператор `??` возвращает первый аргумент, если он определён, и второй — в противном случае.
14+
15+
Оператор объединения с null не является чем-то принципиально новым. Это всего лишь удобный синтаксис, как из двух значений получить одно "определённое".
16+
17+
Вот как можно переписать выражение `result = a ?? b`, используя уже знакомые нам операторы:
18+
19+
```js
20+
result = (a !== null && a !== undefined) ? a : b;
21+
```
22+
23+
Как правило, оператор `??` нужен для того, чтобы определить значение по умолчанию для потенциально неопределённой переменной.
24+
25+
Например, в следующем примере, если переменная `user` не определена, покажем модальное окно с надписью `Аноним`:
26+
27+
```js run
28+
let user;
29+
30+
alert(user ?? "Аноним"); // Аноним
31+
```
32+
33+
Конечно, если бы переменная `user` содержала любое значение, кроме `null/undefined`, то мы бы увидели имя пользователя:
34+
35+
```js run
36+
let user = "Иван";
37+
38+
alert(user ?? "Аноним"); // Иван
39+
```
40+
41+
Кроме этого, можно записать последовательность из операторов `??`, чтобы получить первое вычислённое определённое значение из всего списка.
42+
43+
Допустим, у нас есть данные пользователя в переменных `firstName`, `lastName` или `nickName`. Все они могут быть неопределёнными, если отсутствует информация в какой-либо из них.
44+
45+
Выведем имя пользователя, используя одну из этих переменных, а в случае если все они не определены, то покажем "Аноним".
46+
47+
Для этого воспользуемся оператором `??`:
48+
49+
```js run
50+
let firstName = null;
51+
let lastName = null;
52+
let nickName = "Суперкодер";
53+
54+
// показывает первое определённое значение:
55+
*!*
56+
alert(firstName ?? lastName ?? nickName ?? "Аноним"); // Суперкодер
57+
*/!*
58+
```
59+
60+
## Сравнение с ||
61+
62+
Оператор ИЛИ `||` можно использовать для того же, что и `??`, как это было показано в [предыдущей главе](info:logical-operators#or-finds-the-first-truthy-value).
63+
64+
Например, в приведённом выше коде можно заменить `??` на `||` и получить тот же самый результат:
65+
66+
```js run
67+
let firstName = null;
68+
let lastName = null;
69+
let nickName = "Суперкодер";
70+
71+
// показывает первое истинное значение:
72+
*!*
73+
alert(firstName || lastName || nickName || "Аноним"); // Суперкодер
74+
*/!*
75+
```
76+
77+
Оператор ИЛИ `||` существует с самого появления JavaScript, поэтому ранее для решения похожих задач разработчики использовали именно его.
78+
79+
С другой стороны, совсем не так давно появился оператор объединения с null `??` как раз потому, что не все были довольны оператором `||` .
80+
81+
Есть одно тонкое, но важное отличие:
82+
- `||` возвращает первое *истинное* значение.
83+
- `??` возвращает первое *определённое* значение.
84+
85+
Проще говоря, оператор `||` не различает `false`, `0`, пустую строку `""` и `null/undefined`. Для него они все одинаковые, т.е. являются ложными значениями. Если первым аргументом для оператора `||` будет любое из перечисленных значений, то в качестве результата мы получим второй аргумент.
86+
87+
Однако на практике часто требуется использовать стандартное значение только тогда, когда переменная является `null/undefined`. Ведь именно тогда значение действительно неизвестно/не определено.
88+
89+
Например, рассмотрим следующий пример:
90+
91+
```js run
92+
let height = 0;
93+
94+
alert(height || 100); // 100
95+
alert(height ?? 100); // 0
96+
```
97+
98+
Итак, мы получили нулевую высоту.
99+
100+
- `height || 100` проверяет, имеет ли переменная `height` ложное значение, что так и есть,
101+
- поэтому результатом является второй аргумент, т.е. `100`.
102+
- `height ?? 100` проверяет, что переменная `height` содержит `null/undefined`, а поскольку это не так,
103+
- то результатом является сама переменная `height`, т.е. `0`.
104+
105+
Если предположить, что нашим значением может быть нулевая высота, которая не должна заменяться значением по умолчанию, то оператор `??` — это то, что нам нужно.
106+
107+
## Приоритет
108+
109+
Оператор `??` имеет довольно низкий приоритет: `5`, согласно [таблице на MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table).
110+
Таким образом, оператор `??` вычисляется до `=` и `?`, но после большинства других операций, таких как `+`, `*`.
111+
112+
Из этого следует, что если нужно выбрать значение при помощи оператора `??` вместе с другими операторами в выражении, следует добавить круглые скобки:
113+
114+
```js run
115+
let height = null;
116+
let width = null;
117+
118+
// важно: используйте круглые скобки
119+
let area = (height ?? 100) * (width ?? 50);
120+
121+
alert(area); // 5000
122+
```
123+
124+
Однако если опустить скобки, то оператор `*` выполнится первым, так как у него приоритет выше, чем у `??`, а это приведёт к неправильным результатам.
125+
126+
```js
127+
// без круглых скобок
128+
let area = height ?? 100 * width ?? 50;
129+
130+
// ...то же самое, что предыдущее выражение (вероятно, это не то, что нам нужно):
131+
let area = height ?? (100 * width) ?? 50;
132+
```
133+
134+
### Использование ?? вместе с && или ||
135+
136+
По соображениям безопасности JavaScript запрещает использование оператора `??` вместе с `&&` и `||`, если только приоритет явно не указан в круглых скобках.
137+
138+
Выполнение следующего кода приведёт к синтаксической ошибке:
139+
140+
```js run
141+
let x = 1 && 2 ?? 3; // Синтаксическая ошибка
142+
```
143+
144+
Это довольно спорное ограничение, которое было описано в спецификации языка, чтобы избежать ошибок при замене оператора `||` на `??`.
145+
146+
Используйте круглые скобки, чтобы обойти это ограничение:
147+
148+
```js run
149+
*!*
150+
let x = (1 && 2) ?? 3; // Работает без ошибок
151+
*/!*
152+
153+
alert(x); // 2
154+
```
155+
156+
## Итого
157+
158+
- Оператор объединения с null `??` — это быстрый способ получить "определённое" значение из списка.
159+
160+
Используется для присвоения переменным значений по умолчанию:
161+
162+
```js
163+
// будет height=100, если переменная height равна null или undefined
164+
height = height ?? 100;
165+
```
166+
167+
- Оператор `??` имеет очень низкий приоритет, немного выше, чем у `?` и `=`, поэтому при использовании его в выражении возможно потребуются круглые скобки.
168+
- Запрещено использовать вместе с `||` или `&&` без явно указанных круглых скобок.

1-js/02-first-steps/12-while-for/1-loop-last-value/solution.md renamed to 1-js/02-first-steps/13-while-for/1-loop-last-value/solution.md

File renamed without changes.

1-js/02-first-steps/12-while-for/1-loop-last-value/task.md renamed to 1-js/02-first-steps/13-while-for/1-loop-last-value/task.md

File renamed without changes.

1-js/02-first-steps/12-while-for/2-which-value-while/solution.md renamed to 1-js/02-first-steps/13-while-for/2-which-value-while/solution.md

File renamed without changes.

1-js/02-first-steps/12-while-for/2-which-value-while/task.md renamed to 1-js/02-first-steps/13-while-for/2-which-value-while/task.md

File renamed without changes.

1-js/02-first-steps/12-while-for/3-which-value-for/solution.md renamed to 1-js/02-first-steps/13-while-for/3-which-value-for/solution.md

File renamed without changes.

1-js/02-first-steps/12-while-for/3-which-value-for/task.md renamed to 1-js/02-first-steps/13-while-for/3-which-value-for/task.md

File renamed without changes.

1-js/02-first-steps/12-while-for/4-for-even/solution.md renamed to 1-js/02-first-steps/13-while-for/4-for-even/solution.md

File renamed without changes.
File renamed without changes.

1-js/02-first-steps/12-while-for/5-replace-for-while/solution.md renamed to 1-js/02-first-steps/13-while-for/5-replace-for-while/solution.md

File renamed without changes.

0 commit comments

Comments
 (0)