Мы хотим сделать этот проект с открытым исходным кодом доступным для людей во всем мире. Пожалуйста, помогите нам перевести это руководство на другие языки.

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

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

  • || (ИЛИ)
    • ||= (Оператор логического присваивания ИЛИ)
  • && (И)
    • &&= (Оператор логического присваивания И)
  • ! (НЕ)
  • ?? (Оператор нулевого слияния)
    • ??= (Оператор нулевого присваивания)

Здесь мы рассмотрим первые пять, операторы ?? и ??= будут в следующей статье.

Несмотря на своё название, данные операторы могут применяться к значениям любых типов. Полученные результаты также могут иметь различный тип.

Давайте рассмотрим их подробнее.

|| (ИЛИ)

Оператор «ИЛИ» выглядит как двойной символ вертикальной черты:

result = a || b;

Традиционно в программировании ИЛИ предназначено только для манипулирования булевыми значениями: в случае, если какой-либо из аргументов true, он вернёт true, в противоположной ситуации возвращается false.

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

Существует всего четыре возможные логические комбинации:

alert( true || true ); // true alert( false || true ); // true alert( true || false ); // true alert( false || false ); // false

Как мы можем наблюдать, результат операций всегда равен true, за исключением случая, когда оба аргумента false.

Если значение не логического типа, то оно к нему приводится в целях вычислений.

Например, число 1 будет воспринято как true, а 0 – как false:

if (1 || 0) { // работает как if( true || false ) alert( 'истинно!' ); }

Обычно оператор || используется в if для проверки истинности любого из заданных условий.

К примеру:

let hour = 9; if (hour < 10 || hour > 18) { alert( 'Офис закрыт.' ); }

Можно передать и больше условий:

let hour = 12; let isWeekend = true; if (hour < 10 || hour > 18 || isWeekend) { alert( 'Офис закрыт.' ); // это выходной }

ИЛИ "||" находит первое истинное значение

Описанная выше логика соответствует традиционной. Теперь давайте поработаем с «дополнительными» возможностями JavaScript.

Расширенный алгоритм работает следующим образом.

При выполнении ИЛИ || с несколькими значениями:

result = value1 || value2 || value3;

Оператор || выполняет следующие действия:

  • Вычисляет операнды слева направо.
  • Каждый операнд конвертирует в логическое значение. Если результат true, останавливается и возвращает исходное значение этого операнда.
  • Если все операнды являются ложными (false), возвращает последний из них.

Значение возвращается в исходном виде, без преобразования.

Другими словами, цепочка ИЛИ || возвращает первое истинное значение или последнее, если такое значение не найдено.

Например:

alert( 1 || 0 ); // 1 (1 - истинное значение) alert( true || 'какая-то строка' ); // true alert( null || 1 ); // 1 (первое истинное значение) alert( null || 0 || 1 ); // 1 (первое истинное значение) alert( undefined || null || 0 ); // 0 (поскольку все ложно, возвращается последнее значение)

Это делает возможным более интересное применение оператора по сравнению с «чистым, традиционным, только булевым ИЛИ».

  1. Получение первого истинного значения из списка переменных или выражений.

    Например, у нас есть переменные firstName, lastName и nickName, все они необязательные (т.е. они могут быть неопределенными или иметь ложные значения).

    Давайте воспользуемся оператором ИЛИ ||, чтобы выбрать ту переменную, в которой есть данные, и показать её (или «Аноним», если ни в одной переменной данных нет):

    let firstName = ""; let lastName = ""; let nickName = "Суперкодер"; alert( firstName || lastName || nickName || "Аноним"); // Суперкодер

    Если бы все переменные были ложными, в качестве результата мы бы наблюдали "Аноним".

  2. Сокращённое вычисление.

    Ещё одной отличительной особенностью оператора ИЛИ || является так называемое «сокращённое вычисление».

    Это означает, что ИЛИ || обрабатывает свои операнды до тех пор, пока не будет достигнуто первое истинностное значение, и затем это значение сразу же возвращается, даже не затрагивая другие операнды.

    Важность этой особенности становится очевидной, если операнд – это не просто значение, а выражение с сопутствующим эффектом, как, например, присваивание переменной или вызов функции.

    В приведенном ниже примере срабатывает только второй alert:

    true || alert("никогда не сработает"); false || alert("сработает");

    В первой строке оператор ИЛИ || останавливает выполнение сразу после того, как сталкивается с истинным значением (true), поэтому сообщение не показывается.

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

||= (Логическое присваивание ИЛИ)

Новая возможность
Эта возможность была добавлена в язык недавно. В старых браузерах может понадобиться полифил.

Оператор логического присваивания ИЛИ ||= записывается как обычный ИЛИ || с добавлением символа присваивания =. Такая запись не случайна, так как результат выполнения данного оператора напрямую зависит от действий уже известного нам ||.

Вот его синтаксис:

a ||= b;

Оператор ||= принимает два операнда и выполняет следующие действия:

  • Вычисляет операнды слева направо.
  • Конвертирует a в логическое значение.
  • Если a ложно, присваивает a значение b.

Концепция оператора ||= заключается в «сокращённом вычислении», принцип работы которого мы разобрали ранее.

Теперь давайте перепишем a ||= b под вид «сокращённого вычисления»:

a || (a = b);

Мы уже знаем, что ИЛИ || возвращает первое истинное значение, поэтому, если a является таковым, вычисление до правой части выражения не дойдёт.

Вот пример с очевидным использованием оператора ||=:

let johnHasCar = false; johnHasCar ||= "У Джона нет машины!"; // то же самое, что false || (johnHasCar = "...") alert( johnHasCar ); // "У Джона нет машины!"

…А здесь происходит преобразование к логическому значению:

let manufacturer = ""; // оператор ||= преобразует пустую строку "" к логическому значению false manufacturer ||= "Неизвестный производитель"; // то же самое, что false || (manufacturer = "...") alert( manufacturer ); // "Неизвестный производитель"

Оператор логического присваивания ИЛИ ||= – это «синтаксический сахар», добавленный в язык в качестве более короткого варианта записи if-выражений с присваиванием.

Мы можем переписать приведённые выше примеры с использованием обычного if:

let johnHasCar = false; if (johnHasCar == false) { johnHasCar = "У Джона нет машины!"; } alert(johnHasCar); // "У Джона нет машины!" let manufacturer = ""; if (manufacturer == false) { manufacturer = "Неизвестный производитель"; } alert(manufacturer); // "Неизвестный производитель"

&& (И)

Оператор И пишется как два амперсанда &&:

result = a && b;

В традиционном программировании И возвращает true, если оба аргумента истинны, а иначе – false:

alert( true && true ); // true alert( false && true ); // false alert( true && false ); // false alert( false && false ); // false

Пример с if:

let hour = 12; let minute = 30; if (hour == 12 && minute == 30) { alert( 'Время 12:30' ); }

Как и в случае с ИЛИ, любое значение допускается в качестве операнда И:

if (1 && 0) { // вычисляется как true && false alert( "не сработает, так как результат ложный" ); }

И «&&» находит первое ложное значение

При нескольких подряд операторах И:

result = value1 && value2 && value3;

Оператор && выполняет следующие действия:

  • Вычисляет операнды слева направо.
  • Каждый операнд преобразует в логическое значение. Если результат false, останавливается и возвращает исходное значение этого операнда.
  • Если все операнды были истинными, возвращается последний.

Другими словами, И возвращает первое ложное значение. Или последнее, если ничего не найдено.

Вышеуказанные правила схожи с поведением ИЛИ. Разница в том, что И возвращает первое ложное значение, а ИЛИ –  первое истинное.

Примеры:

// Если первый операнд истинный, // И возвращает второй: alert( 1 && 0 ); // 0 alert( 1 && 5 ); // 5 // Если первый операнд ложный, // И возвращает его. Второй операнд игнорируется alert( null && 5 ); // null alert( 0 && "какая-то строка" ); // 0

Можно передать несколько значений подряд. В таком случае возвратится первое «ложное» значение, на котором остановились вычисления.

alert( 1 && 2 && null && 3 ); // null

Когда все значения верны, возвращается последнее

alert( 1 && 2 && 3 ); // 3
Приоритет оператора && больше, чем у ||

Приоритет оператора И && больше, чем ИЛИ ||, так что он выполняется раньше.

Таким образом, код a && b || c && d по существу такой же, как если бы выражения && были в круглых скобках: (a && b) || (c && d).

Не заменяйте if на || или &&

Иногда люди используют оператор И && как «более короткий способ записи if-выражения».

Например:

let x = 1; (x > 0) && alert( 'x больше нуля!' );

Инструкция в правой части && будет выполнена только в том случае, если вычисление дойдет до нее. То есть, только если (x > 0) истинно.

Таким образом, мы имеем аналог для следующего кода:

let x = 1; if (x > 0) alert( 'x больше нуля!' );

Несмотря на то, что вариант с && кажется более коротким, if более нагляден и, как правило, более читабелен. Поэтому мы рекомендуем использовать каждую конструкцию по назначению: использовать if, если нам нужно if, и использовать &&, если нам нужно И.

&&= (Логическое присваивание И)

Новая возможность
Эта возможность была добавлена в язык недавно. В старых браузерах может понадобиться полифил.

Оператор логического присваивания И &&= записывается как два амперсанда && и символ присваивания =.

Вот его синтаксис:

a &&= b;

Принцип действия &&= практически такой же, как и у оператора логического присваивания ИЛИ ||=. Единственное отличие заключается в том, что &&= присвоит a значение b только в том случае, если a истинно.

Концепция оператора логического присваивания И &&= также основывается на «сокращённом вычислении»:

a && (a = b);

Пример использования:

let greeting = "Привет"; // строка непустая, поэтому будет преобразована к логическому значению true оператором &&= greeting &&= greeting + ", пользователь!"; // то же самое, что true && (greeting = greeting + "...") alert( greeting ) // "Привет, пользователь!"

Так как оператор логического присваивания И &&= также как и ||= является «синтаксическим сахаром», мы можем без проблем переписать пример выше с использованием привычного для нас if:

let greeting = "Привет"; if (greeting) { greeting = greeting + ", пользователь!" } alert( greeting ) // "Привет, пользователь!"

На практике, в отличие от ||=, оператор &&= используется достаточно редко – обычно, в комбинации с более сложными языковыми конструкциями, о которых мы будем говорить позже. Подобрать контекст для применения данного оператора – довольно непростая задача.

! (НЕ)

Оператор НЕ представлен восклицательным знаком !.

Синтаксис довольно прост:

result = !value;

Оператор принимает один аргумент и выполняет следующие действия:

  1. Сначала приводит аргумент к логическому типу true/false.
  2. Затем возвращает противоположное значение.

Например:

alert( !true ); // false alert( !0 ); // true

В частности, двойное НЕ !! используют для преобразования значений к логическому типу:

alert( !!"непустая строка" ); // true alert( !!null ); // false

То есть первое НЕ преобразует значение в логическое значение и возвращает обратное, а второе НЕ снова инвертирует его. В конце мы имеем простое преобразование значения в логическое.

Есть немного более подробный способ сделать то же самое – встроенная функция Boolean:

alert( Boolean("непустая строка") ); // true alert( Boolean(null) ); // false

Приоритет НЕ ! является наивысшим из всех логических операторов, поэтому он всегда выполняется первым, перед && или ||.

Задачи

важность: 5

Что выведет код ниже?

alert( null || 2 || undefined );

Ответ: 2, это первое значение, которое в логическом контексте даст true.

alert( null || 2 || undefined );
важность: 3

Что выведет код ниже?

alert( alert(1) || 2 || alert(3) );

Ответ: сначала 1, затем 2.

alert( alert(1) || 2 || alert(3) );

Вызов alert не возвращает значения, или, иначе говоря, возвращает undefined.

  1. Первый оператор ИЛИ || выполнит первый alert(1).
  2. Получит undefined и пойдёт дальше, ко второму операнду в поисках истинного значения.
  3. Так как второй операнд 2 является истинным, то вычисления завершатся, результатом undefined || 2 будет 2, которое будет выведено внешним alert( .... ).

Второй оператор || не будет выполнен, выполнение до alert(3) не дойдёт, поэтому 3 выведено не будет.

важность: 5

Что выведет код ниже?

alert( 1 && null && 2 );

Ответ: null, потому что это первое «ложное» значение из списка.

alert( 1 && null && 2 );
важность: 3

Что выведет код ниже?

alert( alert(1) && alert(2) );

Ответ: 1, а затем undefined.

alert( alert(1) && alert(2) );

Вызов alert не возвращает значения, или, иначе говоря, возвращает undefined.

Поэтому до правого alert дело не дойдёт, вычисления закончатся на левом.

важность: 5

Что выведет код ниже?

alert( null || 2 && 3 || 4 );

Ответ: 3.

alert( null || 2 && 3 || 4 );

Приоритет оператора && выше, чем ||, поэтому он выполнится первым.

Результат 2 && 3 = 3, поэтому выражение приобретает вид:

null || 3 || 4

Теперь результатом является первое истинное значение: 3.

важность: 2

Что выведет код ниже?

let value = NaN; value &&= 10; value ||= 20; value &&= 30; value ||= 40; alert(value);

Ответ: 30.

let value = NaN; value &&= 10; value ||= 20; value &&= 30; value ||= 40; alert(value);

Порядок выполнения данного кода:

  1. value &&= 10
    • value=NaN
    • NaN конвертируется в логическое значение false
    • value ложно, поэтому присваивание не срабатывает
  2. value ||= 20
    • value=NaN
    • NaN конвертируется в логическое значение false
    • value ложно, поэтому присваивание срабатывает
  3. value &&= 30
    • value=20
    • 20 конвертируется в логическое значение true
    • value истинно, поэтому присваивание срабатывает
  4. value ||= 40
    • value=30
    • 30 конвертируется в логическое значение true
    • value истинно, поэтому присваивание не срабатывает
важность: 3

Напишите условие if для проверки, что переменная age находится в диапазоне между 14 и 90 включительно.

«Включительно» означает, что значение переменной age может быть равно 14 или 90.

if (age >= 14 && age <= 90)
важность: 3

Напишите условие if для проверки, что значение переменной age НЕ находится в диапазоне 14 и 90 включительно.

Напишите два варианта: первый с использованием оператора НЕ !, второй – без этого оператора.

Первый вариант:

if (!(age >= 14 && age <= 90))

Второй вариант:

if (age < 14 || age > 90)
важность: 5

Какие из перечисленных ниже alert выполнятся?

Какие конкретно значения будут результатами выражений в условиях if(...)?

if (-1 || 0) alert( 'first' ); if (-1 && 0) alert( 'second' ); if (null || -1 && 1) alert( 'third' );

Ответ: первое и третье выполнятся.

Подробности:

// Выполнится. // Результат -1 || 0 = -1, в логическом контексте true if (-1 || 0) alert( 'first' ); // Не выполнится // -1 && 0 = 0, в логическом контексте false if (-1 && 0) alert( 'second' ); // Выполнится // оператор && имеет больший приоритет, чем || // так что -1 && 1 выполнится раньше // вычисления: null || -1 && 1 -> null || 1 -> 1 if (null || -1 && 1) alert( 'third' );
важность: 3

Напишите код, который будет спрашивать логин с помощью prompt.

Если посетитель вводит «Админ», то prompt запрашивает пароль, если ничего не введено или нажата клавиша Esc – показать «Отменено», в противном случае отобразить «Я вас не знаю».

Пароль проверять так:

  • Если введён пароль «Я главный», то выводить «Здравствуйте!»,
  • Иначе – «Неверный пароль»,
  • При отмене или в случае если ничего не введено – «Отменено».

Блок-схема:

Для решения используйте вложенные блоки if. Обращайте внимание на стиль и читаемость кода.

Подсказка: передача пустого ввода в приглашение prompt возвращает пустую строку ''. Нажатие клавиши Esc во время запроса возвращает null.

Запустить демо

let userName = prompt("Кто там?", ''); if (userName === 'Админ') { let pass = prompt('Пароль?', ''); if (pass === 'Я главный') { alert( 'Здравствуйте!' ); } else if (pass === '' || pass === null) { alert( 'Отменено' ); } else { alert( 'Неверный пароль' ); } } else if (userName === '' || userName === null) { alert( 'Отменено' ); } else { alert( "Я вас не знаю" ); }

Обратите внимание на вертикальные отступы внутри блоков if. Они технически не требуются, но делают код более читаемым.

Карта учебника