Оператор нулевого слияния

Оператор нулевого слияния

Наши соц. сети: instagram, fb, tg

Оператор нулевого слияния - одна из тех вещей, которые на первый взгляд кажутся простыми, но могут оказаться сложными на практике. В этой статье мы постараемся разобраться, что это за оператор, как он работает и как его использовать. Также мы рассмотрим некоторые ошибки, связанные с логическими операторами и их возможные решения.

Проблемы использования логических операторов

Долгое время JavaScript поддерживал только три логических оператора. Эти операторы известны всем новичкам: ИЛИ, И и НЕ. Они позволяют выполнять различные задачи в зависимости от текущих условий. И все бы хорошо, и все бы прекрасно, если бы у этих операторов не было своих ошибок. Они отлично работают с логическими значениями, например, в условных выражениях. Когда мы используем их с различными типами данных, JavaScript преобразует эти типы данных в логические. Это не вызывает никаких сложностей, если мы работаем со значениями true, null или undefined. Проблемы могут возникнуть при работе с 0 или " " (пустая строка), так как JavaScript преобразует эти значения в false. Когда нам нужно получить доступ к свойству объекта только в том случае, если у этого свойства есть какое-то значение. Если мы будем использовать ИЛИ, то в этом случае наш код может быть неверно реализован при значениях свойств 0 или “ “. Давайте проиллюстрируем это на одном простом примере. Допустим, нам нужно получить доступ к некоторому свойству объекта, только если оно имеет какое-то значение. Если оно не имеет никакого значения, мы хотим использовать значения по умолчанию. Можно сделать это с помощью логического оператора ИЛИ. В этом случае JavaScript преобразует значения 0 и ” ” в false, а оператор ИЛИ вернет значение по умолчанию. Напомню, что ложные значения в JavaScript - это false, 0, -0, 0n, " " (пустая строка), null, undefined и NaN. Любое другое значение преобразуется в true.

const user = {
    name: 'Вася Пупкин',
    age: 0, // 0 интерпретируется как ложное значение
    jobTitle: '', // пустая строка интерпретируется как ложное значение
    hobbies: null // null также является ложным
}

console.log(user.name || 'Гость') ;
// здесь все хорошо
// в консоли 'Вася Пупкин'

console.log(user.age || 29) ;
// здесь код дает сбой
// свойство существует, значение его = 0
// а на выходе мы получаем 29

console.log(user.jobTitle || 'Безработный') ;
// здесь снова сбой (значение существует, хоть это и пустая строка)
// а на выходе ‘Безработный'

console.log(user.hobbies || 'Нет хобби.') ;
// при работе с null все работает как нужно
// на выходе 'Нет хобби.'

console.log(user.height || 'Нет данных о росте') ;
// при вызове несуществующего свойства получим false
// выведет 'Нет данных о росте'

Исправляем ошибки

Когда логический оператор ИЛИ встречает ложное значение, он возвращает правый операнд (значение, которое вы указали справа будет значением по умолчанию). Это то, что произошло в примере выше, когда мы пытались получить доступ к свойствам age и jobTitle. Оба значения интерпретируются как false, и логический оператор возвращает значение по умолчанию. Есть способ это исправить. Для этого мы сначала проверим, равно ли свойство null или undefined, используя оператор И. Если свойство не является ни null, ни undefined, то свойство существует и мы попытаемся получить к нему доступ и вернуть его значение. В противном случае код вернет значение по умолчанию. Можно также сделать это с помощью оператора if ... else или тренарного оператора ”?”.


const user = {
    name: 'Вася Пупкин',
    age: 0, // 0 интерпретируется как ложное значение
    jobTitle: '', // пустая строка интерпретируется как ложное значение
    hobbies: null // null также является ложным
}

console.log((user.name !== null && user.name !== undefined) ? user.name : 'Гость') ;
// Работает как нужно
//  Выводит:  'Вася Пупкин'

console.log((user.age !== null && user.age !== undefined) ? user.age : 29) ;
// Теперь тоже как нужно
// 0

console.log((user.jobTitle !== null && user.jobTitle !== undefined) ? user.jobTitle : 'Безработный') ;
// ''

console.log((user.hobbies !== null && user.hobbies !== undefined) ? user.hobbies : 'Нет хобби')
// 'Нет хобби.'

console.log(user.height !== null && user.height !== undefined ? user.height : 'Нет данных о росте') ;
// 'Нет данных о росте'

Оператор нулевого слияния

Отлично, мы исправили возможные ошибки с помощью оператора И. Такое решение работает, но загромождает наш код и делает его менее читабельным. Лучшим же решением будет оператор нулевого слияния “??”, добавленный в ES2020. Можно сказать, что оператор ?? является сокращением для тернарного оператора ?. С помощью него мы можем узнать, является ли операнд с левой стороны null или undefined. Если так, то ”??” вернет значение по умолчанию. В противном случае он вернет операнд с левой стороны. Давайте вернемся к примеру с объектом user и используем нулевой оператор слияния для записи существующих свойств или значений по умолчанию. Мы можем удалить весь тернарный оператор. После этого нам просто нужно заменить двоеточия на ”??”. Как видно из приведенного ниже примера, код станет намного короче и читабельнее.

user = {
 name: 'Вася Пупкин',
 age: 0, // 0 интерпретируется как ложное значение
 jobTitle: '', // пустая строка интерпретируется как ложное значение
 hobbies: null // null также является ложным
}

console.log(user.name ?? 'Гость');
// Работает как нужно
//  Выводит:  'Вася Пупкин'

console.log(user.age ?? 29);
// Теперь тоже как нужно
// 0

console.log(user.jobTitle ?? 'Безработный');
// ''

console.log(user.hobbies ?? 'Нет хобби.');
// 'Нет хобби.'

console.log(user.height ?? 'Нет данных о росте');
// 'Нет данных о росте'

Комбинируем ?? с другими логическими операторами

Следует помнить одну вещь: нельзя просто так использовать оператор нулевого слияния с другими логическими операторами. В этом случае JavaScript выдает синтаксическую ошибку. Чтобы этого избежать, нужно заключить логический оператор и его операнды в круглые скобки и только после этого добавить оператор нулевого слияния и его операнд.

// Не сработает
console.log(null || undefined ?? 'Какая-нибудь строка');
// SyntaxError: Unexpected token '??'

console.log(null || false ?? 'Какая-нибудь строка');   
// SyntaxError: Unexpected token '??'

console.log(true || false ?? 'Какая-нибудь строка');
// SyntaxError: Unexpected token '??'

// А так сработает
console.log((null || undefined) ?? 'Какая-нибудь строка');
// ‘Какая-нибудь строка'

console.log((null || false) ?? 'Какая-нибудь строка') ;
// false

console.log((true || false) ?? 'Какая-нибудь строка');
// true

Приоритет оператора”??”

В JavaScript у каждого оператора есть приоритет, который определяет, в каком порядке выполняются действия. Каждому оператору присваивается некоторое число, которое определяет этот приоритет. Самый высокий приоритет оператора в настоящее время равен 21. Самый низкий - 1. Операторы с более высоким приоритетом работают перед операторами с более низким приоритетом. Вы можете посмотреть приоритет всех операторов здесь. Приоритет оператора нулевого слияния равен 5. Приоритет оператора ИЛИ равен 6, а приоритет И равен 7. Это означает что, если мы используем “??” в более сложных выражениях, то вероятнее всего он будет выполнен одним из последних. По-этому, используя “??” в выражениях, следует оборачивать его в скобки.

const hoursWorked = null;
const hourlyRate = null;

// без скобок
hoursWorked ?? 1 * hourlyRate ?? 25
// 0
// так как hoursWorked * hourlyRate = 0 (null * null = 0)

// в скобках
(hoursWorked ?? 1) * (hourlyRate ?? 25)
// 25

Вывод:

Оператор нулевого слияния ”??” поможет упростить ваш код и сделать его более читабельным. Однако следует помнить, что у него довольно низкий приоритет. Поэтому при использовании в сложных выражениях его следует обернуть в скобки. Я надеюсь, что это руководство помогло вам понять, как работает оператор нулевого слияния, и как использовать его для написания более чистого и безопасного кода.

Приятного кодинга!