Совместное использование логических и условных операторов. Элемент оператора if: else. Диалоговые окна.

15.11.2022 10:48

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

    В 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( 'truthy!' );
}
Обычно оператор || используется в 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
alert( true || 'no matter what' ); // true
 
alert( null || 1 ); // 1 (первое истинное значение)
alert( null || 0 || 1 ); // 1 (первое истинное значение)
alert( undefined || null || 0 ); // 0 (поскольку все ложно, возвращается последнее значение)
Это делает возможным более интересное применение оператора по сравнению с «чистым, традиционным, только булевым ИЛИ».
 
1. Получение первого истинного значения из списка переменных или выражений.
 
Представим, что у нас имеется ряд переменных, которые могут содержать данные или быть null/undefined. Как мы можем найти первую переменную с данными?
 
С помощью ||:
 
let currentUser = null;
let defaultUser = "John";
 
let name = currentUser || defaultUser || "unnamed";
 
alert( name ); // выбирается "John" – первое истинное значение
Если бы и currentUser, и defaultUser были ложными, в качестве результата мы бы наблюдали "unnamed".
 
2. Сокращённое вычисление.
 
Операндами могут быть как отдельные значения, так и произвольные выражения. ИЛИ || вычисляет их слева направо. Вычисление останавливается при достижении первого истинного значения. Этот процесс называется «сокращённым вычислением», поскольку второй операнд вычисляется только в том случае, если первого недостаточно для вычисления всего выражения.
 
Это хорошо заметно, когда выражение, указанное в качестве второго аргумента, имеет побочный эффект, например, изменение переменной.
 
В приведённом ниже примере x не изменяется:
 
let x;
 
true || (x = 1);
 
alert(x); // undefined, потому что (x = 1) не вычисляется
Если бы первый аргумент имел значение false, то || приступил бы к вычислению второго и выполнил операцию присваивания:
 
let x;
 
false || (x = 1);
 
alert(x); // 1
 

    Присваивание – лишь один пример. Конечно, могут быть и другие побочные эффекты, которые не проявятся, если вычисление до них не дойдёт.

    Как мы видим, этот вариант использования || является "аналогом if". Первый операнд преобразуется в логический. Если он оказывается ложным, начинается вычисление второго.

    В большинстве случаев лучше использовать «обычный» if, чтобы облегчить понимание кода, но иногда это может быть удобно.

 

&& (И)

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

 

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( 'The time is 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 && "no matter what" ); // 0
Можно передать несколько значений подряд. В таком случае возвратится первое «ложное» значение, на котором остановились вычисления.
 
alert( 1 && 2 && null && 3 ); // null
Когда все значения верны, возвращается последнее
 
alert( 1 && 2 && 3 ); // 3
Приоритет оператора && больше, чем у ||
Приоритет оператора И && больше, чем ИЛИ ||, так что он выполняется раньше.
 
Таким образом, код a && b || c && d по существу такой же, как если бы выражения && были в круглых скобках: (a && b) || (c && d).
 
Как и оператор ИЛИ ||, И && иногда может заменять if.
 
К примеру:
 
let x = 1;
 
(x > 0) && alert( 'Greater than zero!' );
Действие в правой части && выполнится только в том случае, если до него дойдут вычисления. То есть, alert сработает, если в левой части (x > 0) будет true.
 
Получился аналог:
 
let x = 1;
 
if (x > 0) {
  alert( 'Greater than zero!' );
}
Однако, как правило, вариант с if лучше читается и воспринимается.
 
Он более очевиден, поэтому лучше использовать его.
 

! (НЕ)

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

Синтаксис довольно прост:
 
result = !value;
 
Оператор принимает один аргумент и выполняет следующие действия:
  • Сначала приводит аргумент к логическому типу true/false.
  • Затем возвращает противоположное значение.

Например:

 
alert( !true ); // false
alert( !0 ); // true
В частности, двойное НЕ !! используют для преобразования значений к логическому типу:
 
alert( !!"non-empty string" ); // true
alert( !!null ); // false

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

 
    Есть немного более подробный способ сделать то же самое – встроенная функция Boolean:
 
alert( Boolean("non-empty string") ); // true
alert( Boolean(null) ); // false

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

 

Ветвления в программе - оператор if

    Очень часто возникает ситуация, когда нам нужно выполнить какое-либо действие в зависимости от какого-либо условия. Например, у нас интернет-магазин одежды. Мы спрашиваем у пользователя кто он (мужчина или женщина) и в зависимости от ответа отображаем список соответствующих товаров (мужских или женских). При написании подобных программ используется условный оператор if . 

    Синтаксис у него следующий:

 
if B {S1}
else {S2}
 
 
где B - выражение логического типа, а S1 и S2 - операторы.
 

    Работает это так: вычисляется значение выражения B, если оно истинно, то выполняется оператор S1, если оно ложно, то выполняется оператор S2. Строку else {S2} можно опустить.

    Думаю на примере будет понятнее. Пусть у нас есть форма, в которую пользователь вводит 3 значения. Напишем сценарий, который определит максимальное из введеных чисел.

 
Для начала напишем в html-странице код формы:
 
    <html>
        <head>
            <title>javascript if</title>
            <link rel="stylesheet" type="text/css" href="style1.css">
            <script type="text/javascript" src="script.js"></script>
        </head>
        <body>
            <form name="forma4">
                Значение 1 <input type="text" size="8" maxlength="8" name="zn1">
                Значение 2 <input type="text" size="8" maxlength="8" name="zn2">
                Значение 3 <input type="text" size="8" maxlength="8" name="zn3"><br><br>
                <input type="button" value="Максимальное значение" onClick="maxZnach(forma4);">
                <input type="text" size="8" maxlength="8" name="res">
                <input type="reset" value="Отменить">
            </form>
        </body>
    </html>
 
Теперь на странице script.js напишем код функции:
 
function maxZnach(obj){
  var a=1*obj.zn1.value;
  var b=1*obj.zn2.value;
  var c=1*obj.zn3.value;
  var m=a;
  if (b>m) m=b;
  if (c>m) m=c;
  obj.res.value=m;
}
 

    Итак, наша функция принимает три значения из формы, за максимальное (m) мы принимаем значение a. Затем мы сравниваем: если значение b больше максимального (т.е. a), то максимальным становится b, в противном случае максимальным остается a (т.к. выражение в скобках не является истинным). Далее аналогично сравниваем следующее значение c с максимальным. Ответ выводим в поле результата (res).

 
    Вообще такой сценарий можно было бы написать, используя метод max объекта Math, рассмотренного в прошлом уроке, и код получился бы короче:
 
function maxZnach(obj){
  var a=1*obj.zn1.value;
  var b=1*obj.zn2.value;
  var c=1*obj.zn3.value;
  obj.res.value=Math.max(Math.max(a,b),c);
}
 

    Это я к тому, что программирование все-таки процесс творческий, и одну задачу можно решить разными способами. Задача же программиста найти наиболее оптимальный вариант. Но это так, лирическое отступление. Вернемся к условному оператору if и рассмотрим более интересный пример. Напишем сценарий, во-время работы которого, при наведении курсора мыши на изображение, оно будет увеличиваться, создавая эффект приближения.

    Как вы помните в HTML можно задать размер вставляемого изображения. Если заданные размеры больше или меньше оригинала, то браузер автоматически подгонит оригинал под эти размеры. Этим мы и воспользуемся. Пусть у нас есть вот такая картинка:
 

    Ширина оригинала 190 пикселей. Мы же хотим, чтобы на странице картинка имела ширину 100 пикселей, а при наведении курсора, увеличивалась до 190 пикселов. Для написания примера можно использовать данную картинку.

 
С html-страницей все понятно:
 
    <html>
        <head>
            <title>javascript if</title>
            <link rel="stylesheet" type="text/css" href="style1.css">
            <script type="text/javascript" src="script.js"></script>
        </head>
        <body>
          <img src="images/tigrenok.jpg" name="tigr" width="100" onMouseOver="bigPict()">
        </body>
    </html>
 

    А в нашей функции, кроме условного оператора, мы воспользуемся еще стандартной функцией javascript setTimeout, которая вызывает пользовательскую функцию с заданным промежутком времени:

 
    function bigPict(){
     var w=document.tigr.width;
     if (w<190){
      document.tigr.width=w+10;
      document.tigr.src="robo001.jpg"
      setTimeout("bigPict()", 500)
     }
    }
 

    Таким образом, функция проверяет ширину картинки (width) и, если она меньше 190 пикселов, то увеличивает эту ширину на 10 пикселов. Функция setTimeout вызывает нашу функцию bigPict каждые полсекунды, благодаря чему размер картинки будет увеличиваться до тех пор, пока условие w<190 не станет ложным.

    Чтобы визуально сделать приближение более плавным попробуйте уменьшить шаг увеличения ширины и время обращения к функции. Поиграйтесь с этими числами и найдите наиболее оптимальные.

 

Диалоговые окна в JavaScript: alert, prompt и confirm

    Так как мы будем использовать браузер как демо-среду, нам нужно познакомиться с несколькими функциями его интерфейса, а именно: alert, prompt и confirm.

 

alert

    Эта функция показывает сообщение и ждёт, пока пользователь нажмёт кнопку «ОК».

 
Например:
 
alert("Hello");
Это небольшое окно с сообщением называется модальным окном. Понятие модальное означает, что пользователь не может взаимодействовать с интерфейсом остальной части страницы, нажимать на другие кнопки и т.д. до тех пор, пока взаимодействует с окном. В данном случае – пока не будет нажата кнопка «OK».
 

prompt

    Функция prompt принимает два аргумента:

 
result = prompt(title, [default]);
 
Этот код отобразит модальное окно с текстом, полем для ввода текста и кнопками OK/Отмена.
 
title
Текст для отображения в окне.
default
Необязательный второй параметр, который устанавливает начальное значение в поле для текста в окне.
Квадратные скобки в синтаксисе [...]
Квадратные скобки вокруг default в описанном выше синтаксисе означают, что параметр факультативный, необязательный.
 
Пользователь может напечатать что-либо в поле ввода и нажать OK. Введённый текст будет присвоен переменной result. Пользователь также может отменить ввод нажатием на кнопку «Отмена» или нажав на клавишу Esc. В этом случае значением result станет null.
 
Вызов prompt возвращает текст, указанный в поле для ввода, или null, если ввод отменён пользователем.
 
Например:
 
let age = prompt('Сколько тебе лет?', 100);
 
alert(`Тебе ${age} лет!`); // Тебе 100 лет!
Для IE: всегда устанавливайте значение по умолчанию
Второй параметр является необязательным, но если не указать его, то Internet Explorer вставит строку "undefined" в поле для ввода.
 
Запустите код в Internet Explorer и посмотрите на результат:
 
let test = prompt("Test");
Чтобы prompt хорошо выглядел в IE, рекомендуется всегда указывать второй параметр:
 
let test = prompt("Test", ''); // <-- для IE
 

confirm

Синтаксис:

 
result = confirm(question);

    Функция confirm отображает модальное окно с текстом вопроса question и двумя кнопками: OK и Отмена. Результат – true, если нажата кнопка OK. В других случаях – false.

 
Например:
 
let isBoss = confirm("Ты здесь главный?");
 
alert( isBoss ); // true, если нажата OK
 
Таким образом, мы рассмотрели 3 функции браузера для взаимодействия с пользователем:
 

-alert

показывает сообщение.

-prompt

показывает сообщение и запрашивает ввод текста от пользователя. Возвращает напечатанный в поле ввода текст или null, если была нажата кнопка «Отмена» или Esc с клавиатуры.

-confirm

показывает сообщение и ждёт, пока пользователь нажмёт OK или Отмена. Возвращает true, если нажата OK, и false, если нажата кнопка «Отмена» или Esc с клавиатуры.

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

    На все указанные методы распространяются два ограничения:

  • Расположение окон определяется браузером. Обычно окна находятся в центре.
  • Визуальное отображение окон зависит от браузера, и мы не можем изменить их вид. 

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