Оператор нулевого слияния (??)
Оператор нулевого слияния представляет собой два вопросительных знака ??
.
Так как он обрабатывает null
и undefined
одинаковым образом, то для этой статьи мы введём специальный термин. Для краткости будем говорить, что значение «определено», если оно не равняется ни null
, ни undefined
.
Результат выражения a ?? b
будет следующим:
- если
a
определено, тоa
, - если
a
не определено, тоb
.
Иначе говоря, оператор ??
возвращает первый аргумент, если он не null/undefined
, иначе второй.
Оператор нулевого слияния не является чем-то принципиально новым. Это всего лишь удобный синтаксис, как из двух значений получить одно, которое «определено».
Вот как можно переписать выражение result = a ?? b
, используя уже знакомые нам операторы:
result = (a !== null && a !== undefined) ? a : b;
Теперь должно быть абсолютно ясно, что делает ??
. Давайте посмотрим, где это может быть полезно.
Как правило, оператор ??
нужен для того, чтобы задать значение по умолчанию для потенциально неопределённой переменной.
Например, здесь мы отобразим user
, если её значение не null/undefined
, в противном случае Аноним
:
let user;
alert(user ?? "Аноним"); // Аноним (user не существует)
А вот пример, когда user
присвоено значение:
let user = "Иван";
alert(user ?? "Аноним"); // Иван (user существует)
Кроме этого, можно записать последовательность из операторов ??
, чтобы получить первое значение из списка, которое не является null/undefined
.
Допустим, у нас есть данные пользователя в переменных firstName
, lastName
или nickName
. Все они могут не существовать, если пользователь решил не вводить соответствующие значение.
Мы хотели бы отобразить имя пользователя, используя одну из этих переменных, или показать «Аноним», если все они null/undefined
.
Для этого воспользуемся оператором ??
:
let firstName = null;
let lastName = null;
let nickName = "Суперкодер";
// показывает первое значение, которое определено:
alert(firstName ?? lastName ?? nickName ?? "Аноним"); // Суперкодер
Сравнение с ||
Оператор ИЛИ ||
можно использовать для того же, что и ??
, как это было показано в предыдущей главе.
Например, если в приведённом выше коде заменить ??
на ||
, то будет тот же самый результат:
let firstName = null;
let lastName = null;
let nickName = "Суперкодер";
// показывает первое истинное значение:
alert(firstName || lastName || nickName || "Аноним"); // Суперкодер
Исторически сложилось так, что оператор ИЛИ ||
появился первым. Он существует с самого начала в JavaScript, поэтому разработчики долгое время использовали его для таких целей.
С другой стороны, сравнительно недавно в язык был добавлен оператор нулевого слияния ??
– как раз потому, что многие были недовольны оператором ||
.
Важное различие между ними заключается в том, что:
||
возвращает первое истинное значение.??
возвращает первое определённое значение.
Проще говоря, оператор ||
не различает false
, 0
, пустую строку ""
и null/undefined
. Для него они все одинаковы, т.е. являются ложными значениями. Если первым аргументом для оператора ||
будет любое из перечисленных значений, то в качестве результата мы получим второй аргумент.
Однако на практике часто требуется использовать значение по умолчанию только тогда, когда переменная является null/undefined
. Ведь именно тогда значение действительно неизвестно/не определено.
Рассмотрим следующий пример:
let height = 0;
alert(height || 100); // 100
alert(height ?? 100); // 0
height || 100
проверяетheight
на ложное значение, оно равно0
, да, ложное.- поэтому результатом
||
является второй аргумент, т.е.100
.
- поэтому результатом
height ?? 100
проверяет, что переменнаяheight
содержитnull/undefined
, а поскольку это не так,- то результатом является сама переменная
height
, т.е.0
.
- то результатом является сама переменная
На практике нулевая высота часто является вполне нормальным значением, которое не с��едует заменять значением по умолчанию. Таким образом, ??
здесь как раз работает так, как нужно.
Приоритет
Приоритет оператора ??
такой же, как и у ||
. Они оба равны 3
в таблице на MDN.
Это означает, что, как и ||
, оператор нулевого слияния ??
вычисляется до =
и ?
, но после большинства других операций, таких как +
, *
.
Так что, в выражениях такого вида понадобятся скобки:
let height = null;
let width = null;
// важно: используйте круглые скобки
let area = (height ?? 100) * (width ?? 50);
alert(area); // 5000
Иначе, если опустить скобки, оператор *
выполнится первым, так как у него приоритет выше, чем у ??
, и это приведёт к неправильным результатам.
// без скобок
let area = height ?? 100 * width ?? 50;
// ...сработает вот так (совсем не как нам нужно):
let area = height ?? (100 * width) ?? 50;
Использование ?? вместе с && или ||
По соображениям безопасности JavaScript запрещает использование оператора ??
вместе с &&
и ||
, если приоритет явно не указан при помощи круглых скобок.
Выполнение следующего кода приведёт к синтаксической ошибке:
let x = 1 && 2 ?? 3; // Синтаксическая ошибка
Это, безусловно, спорное ограничение было добавлено в спецификацию языка с целью избежать программные ошибки, когда люди начнут переходить с ||
на ??
.
Используйте скобки, чтобы обойти это ограничение:
let x = (1 && 2) ?? 3; // Работает без ошибок
alert(x); // 2
Оператор нулевого присваивания (??=)
Предположим, нам необходимо проверить, равна ли переменная null
или undefined
, и если это так — присвоить этой переменной какое-либо другое значение.
Вот как мы сделали бы это сейчас:
let userAge = null;
if (userAge === null || userAge === undefined) {
userAge = 18;
}
Выглядит громоздко, правда? Существует оператор, более подходящий для подобных задач. Вот его синтаксис:
x ??= y
Оператор ??=
присвоит x
значение y
только в том случае, если x
не определено (null
/undefined
).
Теперь попробуем переписать уже знакомый нам фрагмент кода используя новый оператор:
let userAge = null;
userAge ??= 18;
alert(userAge) // 18
Обратите внимание: если бы userAge
не был равен null
/undefined
, то выражение справа от ??=
никогда бы не выполнилось:
let userAge = 18;
userAge ??= alert("не сработает");
userAge ??= 21;
userAge ??= null;
alert(userAge) // по-прежнему 18
Итого
-
Оператор нулевого слияния
??
— это быстрый способ выбрать первое «определённое» значение из списка.Используется для присвоения переменным значений по умолчанию:
// будет height=100, если переменная height равна null или undefined height = height ?? 100;
-
Оператор
??
имеет очень низкий приоритет, лишь немного выше, чем у?
и=
, поэтому при использовании его в выражении, скорее всего, потребуются скобки. -
Запрещено использовать вместе с
||
или&&
без явно указанного приоритета, то есть без скобок. -
Для присвоения переменной значения в зависимости от того, «определена» она или нет, используется оператор нулевого присваивания
??=
.
Комментарии
<code>
, для нескольких строк кода — тег<pre>
, если больше 10 строк — ссылку на песочницу (plnkr, JSBin, codepen…)