NodeJS Back-end Инженер

NodeJS Back-end Инженер

Роадмап навыков для прокачки

Логические операторы

Язык JavaScript (ES5)ОбщееОсновное

Основная идея

Логические операторы в JavaScript (&&, ||, !) используются для комбинирования условий и управления потоком выполнения кода. Они работают не только с булевыми значениями, но и возвращают один из операндов, что делает их мощным инструментом для написания лаконичного кода.

Ключевые аспекты

  • && (AND) — возвращает первое ложное значение или последнее, если все истинные
  • || (OR) — возвращает первое истинное значение или последнее, если все ложные
  • ! (NOT) — инвертирует булево значение
  • Short-circuit evaluation — вычисление прекращается, как только результат становится определён
  • Falsy valuesfalse, 0, "", null, undefined, NaN

Плюсы

  • Краткий синтаксис для условий
  • Удобны для значений по умолчанию (||)
  • Позволяют условно выполнять код (&&)
  • Высокая производительность благодаря короткому замыканию

Минусы

  • Неочевидное поведение с falsy значениями (0, "")
  • Путаница между логическим и побитовым операторами
  • Чрезмерное использование усложняет читаемость

Частые ошибки на собеседованиях

  • Путают приоритет операторов (&& выше чем ||)
  • Забывают, что операторы возвращают операнд, а не true/false
  • Не учитывают, что 0 и "" — falsy значения при использовании ||
  • Путают || с nullish coalescing оператором ?? (ES2020)

Введение и проблематика

Логические операторы — фундаментальная часть любого языка программирования. В JavaScript они имеют особое поведение: вместо возврата true или false они возвращают один из операндов. Это делает их мощным инструментом не только для логических проверок, но и для написания элегантного кода.

В JavaScript логические операторы работают с любыми типами данных, а не только с булевыми значениями. Это ключевое отличие от многих других языков.

Почему это важно?

  • Понимание логических операторов критично для написания условий
  • Короткое замыкание позволяет оптимизировать код
  • Часто используются для значений по умолчанию и условного выполнения

Базовая теория

Три логических оператора

JavaScript имеет три логических оператора:

ОператорНазваниеОписание
&&AND (И)Возвращает первое falsy или последнее значение
||OR (ИЛИ)Возвращает первое truthy или последнее значение
!NOT (НЕ)Инвертирует булево значение

Falsy и Truthy значения

⚠️

Понимание falsy/truthy — ключ к работе с логическими операторами!

Falsy значения (приводятся к false):

js
false       // само значение false
0           // ноль
-0          // минус ноль
""          // пустая строка
null        // отсутствие значения
undefined   // неопределённое значение
NaN         // Not a Number

Truthy значения — всё остальное:

js
true
42          // любое число кроме 0
"hello"     // любая непустая строка
[]          // пустой массив (!)
{}          // пустой объект (!)
function(){} // функция

Пустой массив [] и пустой объект {} — truthy значения! Это частая ловушка.


Практические примеры

Оператор AND (&&)

Возвращает первое falsy значение или последнее значение, если все truthy.

Code Example 1: Что выведет каждый console.log? Какое значение вернёт && если первый операнд falsy?

js
// Примеры с булевыми значениями
console.log(true && true);   // true
console.log(true && false);  // false
console.log(false && true);  // false
 
// Примеры с разными типами
console.log("hello" && 42);       // 42 (оба truthy, возвращает последний)
console.log(0 && "hello");        // 0 (первый falsy)
console.log("" && "hello");       // "" (первый falsy)
console.log("hello" && 0 && 42);  // 0 (первый falsy)

Практическое применение — условное выполнение:

js
// Вызов функции только если условие истинно
const isLoggedIn = true;
isLoggedIn && showDashboard();  // showDashboard() выполнится
 
// Доступ к вложенным свойствам
const user = { profile: { name: "John" } };
const name = user && user.profile && user.profile.name;
console.log(name);  // "John"
 
// Короткая запись условного рендеринга (в React)
{isAdmin && <AdminPanel />}

Оператор OR (||)

Возвращает первое truthy значение или последнее значение, если все falsy.

Code Example 2: Что выведет каждый console.log? Какое значение вернёт || если все операнды falsy?

js
// Примеры с булевыми значениями
console.log(true || false);   // true
console.log(false || true);   // true
console.log(false || false);  // false
 
// Примеры с разными типами
console.log("hello" || 42);      // "hello" (первый truthy)
console.log(0 || "hello");       // "hello" (первый truthy)
console.log("" || 0 || null);    // null (все falsy, возвращает последний)
console.log(null || undefined || "default");  // "default"

Практическое применение — значения по умолчанию:

Code Example 3: Что выведет greet() без аргументов? Почему?

js
// Установка значения по умолчанию
function greet(name) {
  name = name || "Гость";
  console.log("Привет, " + name + "!");
}
 
greet("Иван");  // "Привет, Иван!"
greet();        // "Привет, Гость!"
 
// Получение первого доступного значения
const config = userConfig || defaultConfig || {};
 
// Значение по умолчанию для параметров
const port = process.env.PORT || 3000;

Оператор NOT (!)

Инвертирует булево значение. Сначала приводит операнд к boolean, затем инвертирует.

Code Example 4: Что выведет каждый console.log? Для чего используется !!?

js
console.log(!true);       // false
console.log(!false);      // true
console.log(!"hello");    // false (строка truthy -> инвертируется в false)
console.log(!0);          // true (0 falsy -> инвертируется в true)
console.log(!null);       // true
console.log(![]);         // false (массив truthy!)

Двойное отрицание (!!)

Используется для явного преобразования в boolean:

js
console.log(!!"hello");   // true
console.log(!!0);         // false
console.log(!!null);      // false
console.log(!![]);        // true
 
// Практическое применение
function hasItems(arr) {
  return !!arr && !!arr.length;
}

Короткое замыкание (Short-circuit evaluation)

Короткое замыкание — это оптимизация, при которой второй операнд не вычисляется, если результат уже определён первым.

js
// && — если первый falsy, второй не вычисляется
false && expensiveOperation();  // expensiveOperation НЕ вызовется
 
// || — если первый truthy, второй не вычисляется
true || expensiveOperation();   // expensiveOperation НЕ вызовется
 
// Практический пример
const user = getUser() || createGuestUser();
// createGuestUser() вызовется только если getUser() вернёт falsy

Приоритет операторов

⚠️

Оператор && имеет более высокий приоритет, чем ||!

Code Example 5: Какой результат у каждого выражения? Почему скобки меняют результат?

js
// Без скобок
console.log(true || false && false);  // true
// Интерпретируется как: true || (false && false)
// Равно: true || false = true
 
// Со скобками для ясности
console.log((true || false) && false);  // false
// Равно: true && false = false

Порядок приоритета (от высшего к низшему):

  1. ! (NOT)
  2. && (AND)
  3. || (OR)
js
// Пример комбинации
const result = !false && true || false;
// Шаг 1: !false = true
// Шаг 2: true && true = true
// Шаг 3: true || false = true
console.log(result);  // true

Пограничные кейсы

🚫

Осторожно с 0 и "" при использовании || для значений по умолчанию!

Code Example 6: Какая проблема в Version A? Чем отличается ?? от ||?

js
// Проблема с || и falsy значениями
function setCount(count) {
  count = count || 10;  // Проблема!
  return count;
}
 
setCount(0);    // 10, а не 0! (0 — falsy)
setCount("");   // 10, а не ""
 
// Решение 1: явная проверка
function setCountFixed(count) {
  count = count !== undefined ? count : 10;
  return count;
}
 
// Решение 2: nullish coalescing (ES2020)
function setCountModern(count) {
  count = count ?? 10;  // ?? проверяет только null/undefined
  return count;
}
 
setCountModern(0);    // 0 (правильно!)
setCountModern(null); // 10

Сравнение || и ??

js
// || возвращает первое truthy
0 || 10        // 10
"" || "default" // "default"
false || true  // true
null || "x"    // "x"

Плюсы и минусы

АспектПлюсыМинусы
СинтаксисКраткий и выразительныйМожет быть неочевидным для новичков
ПроизводительностьКороткое замыкание экономит ресурсы
Значения по умолчаниюУдобно через ||Проблемы с 0 и ""
Условное выполнение&& заменяет простые ifЗлоупотребление ухудшает читаемость

Вопросы интервьюера

Q: Что вернёт выражение "hello" && 0 || "world"?

"world". Сначала "hello" && 0 = 0 (первый falsy). Затем 0 || "world" = "world" (первый truthy).

Q: Чем отличается || от ???

|| возвращает первое truthy значение, ?? — первое не-null/undefined. При 0 || 10 получим 10, при 0 ?? 10 получим 0.

Q: Какой приоритет у логических операторов?

! > && > ||. NOT выполняется первым, затем AND, затем OR.

Q: Что такое short-circuit evaluation?

Это оптимизация, при которой второй операнд не вычисляется, если результат уже определён. Для && — если первый falsy, для || — если первый truthy.

Q: Является ли пустой массив truthy или falsy?

Truthy! Пустой массив [] и пустой объект {} — truthy значения, несмотря на то что они "пустые".


Источники

Code Example 1: AND operator (&&)

❓ Что выведет каждый console.log? Какое значение вернёт && если первый операнд falsy?

js
console.log(true && true);
console.log(true && false);
console.log(false && true);
 
console.log("hello" && 42);
console.log(0 && "hello");
console.log("" && "hello");
console.log("hello" && 0 && 42);

Code Example 2: OR operator (||)

❓ Что выведет каждый console.log? Какое значение вернёт || если все операнды falsy?

js
console.log(true || false);
console.log(false || true);
console.log(false || false);
 
console.log("hello" || 42);
console.log(0 || "hello");
console.log("" || 0 || null);
console.log(null || undefined || "default");

Code Example 3: Default values with ||

❓ Что выведет greet() без аргументов? Почему?

js
function greet(name) {
  name = name || "Гость";
  console.log("Привет, " + name + "!");
}
 
greet("Иван");
greet();

Code Example 4: NOT operator and double negation

❓ Что выведет каждый console.log? Для чего используется !!?

js
console.log(!true);
console.log(!false);
console.log(!"hello");
console.log(!0);
console.log(!null);
console.log(![]);
 
console.log(!!"hello");
console.log(!!0);
console.log(!!null);
console.log(!![]);

Code Example 5: Operator priority

❓ Какой результат у каждого выражения? Почему скобки меняют результат?

js
console.log(true || false && false);
 
console.log((true || false) && false);
 
const result = !false && true || false;
console.log(result);

Code Example 6: Problem with || vs ??

❓ Какая проблема в Version A? Чем отличается ?? от ||?

Version A:

js
function setCount(count) {
  count = count || 10;
  return count;
}
 
setCount(0);
setCount("");

Version B:

js
function setCountModern(count) {
  count = count ?? 10;
  return count;
}
 
setCountModern(0);
setCountModern(null);