$ sudo teach IT

В JavaScript часто возникает ситуация, когда нужно принять решение на основе нескольких условий или подставить значение по умолчанию, если данные отсутствуют. Например, при выводе имени пользователя в интерфейсе:

  • Если имя указано — показываем его.
  • Если имя не указано — показываем "Гость".

Для таких сценариев разработчики часто используют логические операторы &&, || и ??. Они позволяют компактно записывать условия, управлять потоком выполнения и обрабатывать значения по умолчанию. В этом уроке мы разберём, как работает ленивая оценка в && и ||, зачем нужен оператор ?? и как их правильно применять.

Что вы узнаете в рамках статьи

  • Что такое ленивая оценка и как она работает.
  • Как использовать || и && для проверки условий и присвоения значений.
  • Чем отличается ?? от ||.
  • В каких случаях можно (и не стоит) применять эти операторы.

Ключевые термины

  • Ленивая оценка (short-circuit evaluation) — механизм, при котором вычисления останавливаются, как только результат выражения становится очевиден.
  • Оператор || (логическое ИЛИ) — возвращает первый истинный операнд или последний, если все ложные.
  • Оператор && (логическое И) — возвращает первый ложный операнд или последний, если все истинные.
  • Оператор ?? (Nullish coalescing) — возвращает первый операнд, который не равен null и undefined.

Ленивая оценка: суть и пример

Ленивая оценка (short-circuit evaluation) — это приём, при котором JavaScript прекращает проверку условий, как только результат становится очевидным.

Представьте, что вы идёте по чек-листу:

  1. "Сегодня хорошая погода?" — Нет → остальные пункты про пикник можно не проверять.
  2. "Есть ли у нас еда?" — Неважно, мы уже решили, что пикник отменяется.

JavaScript действует точно так же:

  • В || (ИЛИ): если хотя бы одно условие true, всё выражение будет true → дальше проверять смысла нет.
  • В && (И): если хотя бы одно условие false, всё выражение будет false → дальше проверять смысла нет.

Пример с ||:

const a = 0;

if (a > -1 || b < 4) {
  console.log("Первое условие выполнилось");
}
  • Шаг 1: Проверяем a > -1 → это true (0 больше -1).
  • Шаг 2: Так как || работает по принципу "нашёл истину — хватит", второе условие (b < 4) даже не вычисляется.
  • Результат: ошибки нет, хотя b не определена.

Пример с &&:

const x = -12;

if (x > -1 && b < 4) {
  console.log("Сообщение не выведется");
} else {
  console.log("А это выведется");
}
  • Шаг 1: x > -1 → false.
  • Шаг 2: Для && это уже достаточно, чтобы вернуть false для всего выражения.
  • Второе условие (b < 4) не проверяется — ошибки нет.

Преимущество: экономия времени и ресурсов.
Опасность: можно забыть, что вторая часть не будет выполняться, и поместить туда важный код.

Оператор || — логическое ИЛИ

Оператор || (логическое ИЛИ) проверяет операнды слева направо и возвращает первый, который приводится к true (truthy). Если таких нет — возвращает последний.

Важно: результатом работы || может быть не только true или false, а любое значение операнда.

Как это работает

операнд1 || операнд2
  • Если операнд1 truthy (истинное значение) → вернуть операнд1, и дальнейшие проверки не выполняются (ленивая оценка).
  • Если операнд1 falsy (ложное значение) → вернуть операнд2.

Truthy — любое значение, которое в логическом контексте считается true.
Falsy — любое значение, которое в логическом контексте считается false.

Пример 1: Истинный первый операнд

const a = 5;
const b = 10;

const result = a || b;
console.log(result); // 5
  • a → truthy (любое ненулевое число — истина)
  • Возвращаем a, b даже не проверяется.

Пример 2: Ложный первый операнд

const a = 0;
const b = 10;

const result = a || b;
console.log(result); // 10
  • a → falsy (0 считается ложью)
  • Возвращаем второй операнд b.

Пример 3: Несколько операндов

|| можно цепочкой использовать для поиска первого truthy-значения:

const result = 0 || '' || null || 'Hello' || 'World';
console.log(result); // 'Hello'
  • 0 → falsy
  • '' → falsy
  • null → falsy
  • 'Hello' → truthy → возвращаем его.

Применение для значений по умолчанию

Один из самых популярных сценариев — подстановка значения, если переменная пуста:

const userInput = ''; // пользователь ничего не ввёл
const username = userInput || 'Anonymous';
console.log(username); // 'Anonymous'
  • userInput пустая строка → falsy
  • Берём 'Anonymous' как запасное значение.

Недостаток ||

|| считает falsy не только null и undefined, но и:

  • 0
  • '' (пустая строка)
  • false
  • NaN

Иногда это мешает. Например:

const pageNumber = 0;
const currentPage = pageNumber || 1;
console.log(currentPage); // 1, хотя мы хотели 0

Здесь || воспринял 0 как ложь и вернул 1, что не всегда правильно.

Решение — использовать оператор ?? (Nullish Coalescing), который реагирует только на null и undefined:

const currentPage = pageNumber ?? 1;
console.log(currentPage); // 0

Оператор && — логическое И

Оператор && (логическое И) проверяет операнды слева направо и возвращает первый, который приводится к false (falsy). Если все операнды истинные — возвращает последний.

В отличие от ||, который ищет первый истинный элемент, && ищет первый ложный.

Как это работает

операнд1 && операнд2
  • Если операнд1 falsy → вернуть операнд1, и дальнейшие проверки не выполняются (ленивая оценка).
  • Если операнд1 truthy → перейти к проверке операнд2 и вернуть его результат.

Truthy и Falsy значения те же, что и у ||.

Пример 1: Первый операнд ложный

const c = 0;
const d = 20;

const result = c && d;
console.log(result); // 0
  • c → falsy (0 — ложь)
  • Возвращаем c, даже не проверяя d.

Пример 2: Первый операнд истинный

const c = 5;
const d = 20;

const result = c && d;
console.log(result); // 20
  • c → truthy
  • Проверяем второй операнд и возвращаем его.

Пример 3: Несколько операндов

const result = 5 && 'Hello' && 42 && true;
console.log(result); // true

Все операнды truthy → возвращаем последний (true).

const result2 = 5 && 0 && 'Hello';
console.log(result2); // 0

Проверка останавливается на первом falsy (0).

Условное выполнение с &&

Часто используется для выполнения кода только при выполнении условия, чтобы не писать if:

discount && (price = price - price / 100 * discount);
  • Если discount truthy → выполняется правая часть и пересчитывается цена.
  • Если discount falsy → правая часть не выполняется, price остаётся без изменений.

Оператор ?? — объединение с nullish-значениями

Оператор ?? (Nullish Coalescing) возвращает первый операнд, который не является null или undefined. Если первый операнд — null или undefined, возвращается второй.

Главная идея — дать значение по умолчанию, но при этом считать 0, пустую строку и false валидными значениями, а не ложными.

Как это работает

операнд1 ?? операнд2
  • Если операнд1 не null и не undefined → вернуть операнд1.
  • Если операнд1 null или undefined → вернуть операнд2.

Пример 1: Значение null

const foo = null;
const bar = 'default';

const result = foo ?? bar;
console.log(result); // 'default'

foo — это null → возвращаем bar.

Пример 2: Значение undefined

let value;
const result = value ?? 100;
console.log(result); // 100

value не инициализирована → undefined → берём 100.

Пример 3: В отличие от ||

const count = 0;

console.log(count || 10); // 10 — потому что 0 считается falsy в `||`
console.log(count ?? 10); // 0 — потому что 0 не null/undefined

Вывод: ?? не заменит 0 или пустую строку, если они осмысленны в вашем коде.

Пример 4: Пустая строка как допустимое значение

const username = '';
const result = username ?? 'Guest';
console.log(result); // '' — пустая строка, а не 'Guest'

Если бы мы использовали ||, получили бы 'Guest', что могло бы быть ошибкой в логике.

Пример 5: С цепочкой вызовов (optional chaining)

?? часто используют вместе с ?. для безопасного доступа к свойствам:

const user = { profile: { name: '' } };
const name = user?.profile?.name ?? 'No name';
console.log(name); // '' — пустая строка, не 'No name'

Это полезно, когда пустое значение — это валидная информация.

Важные моменты

Приоритет у ?? ниже, чем у большинства операторов, поэтому иногда нужны скобки:

const x = 1 + (null ?? 2); // 3

Нельзя напрямую комбинировать ?? с || или && без скобок — это вызовет ошибку:

// Ошибка SyntaxError
let x = null ?? false || true;
// Нужно явно указать порядок
let y = (null ?? false) || true;

Наиболее частые ошибки

  1. Путаница между || и ??

    0 || 'default' // 'default'
    0 ?? 'default' // 0
    
  2. Использование && без понимания возврата значения — иногда забывают, что && возвращает сам операнд, а не просто true/false.

  3. Вложенные тернарники и логические операторы без скобок — ухудшают читаемость.

Наиболее частые вопросы

В: Можно ли использовать ?? с && и || вместе?
О: Да, но стоит быть осторожным и использовать скобки для явного порядка вычислений.

В: Почему || иногда даёт неожиданный результат?
О: Потому что он считает 0, '' и false ложными значениями, даже если они валидны.

В: Что быстрее — if или &&/||?
О: Скорость практически одинакова, но if часто читается проще.

Итоги

Сегодня вы узнали:

  • Как работает ленивая оценка и почему она ускоряет выполнение кода.
  • Как || помогает задавать значения по умолчанию, а && — выполнять код только при истинности условия.
  • Чем ?? отличается от || и когда его лучше использовать.

Эти операторы делают код компактнее, но всегда думайте о читаемости. Если условие сложное — используйте if.