Урок 3 из 18
В прогрессе

3. Динамическая типизация. Условия if, swith

Строгий режим — "use strict"

Директива выглядит как строка: "use strict" или 'use strict'. Когда она находится в начале скрипта, весь сценарий работает в «современном» режиме.

Методы взаимодействия с пользователем

alert

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

Например:

 
 
alert("Hello");

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

prompt

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

result = prompt(title, [default]);

Этот код отобразит модальное окно с текстом, полем для ввода текста и кнопками OK/Отмена.

title
Текст для отображения в окне.
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

Преобразование типов

 

Строковое преобразование

Строковое преобразование происходит, когда требуется представление чего-либо в виде строки.

Например, alert(value) преобразует значение к строке.

Также мы можем использовать функцию String(value), чтобы преобразовать значение к строке:

 
 
let value = true;
alert(typeof value); // boolean

value = String(value); // теперь value это строка "true"
alert(typeof value); // string

Преобразование происходит очевидным образом. false становится "false"null становится "null" и т.п.

Численное преобразование

Численное преобразование происходит в математических функциях и выражениях.

Например, когда операция деления / применяется не к числу:

 
 
alert( "6" / "2" ); // 3, строки преобразуются в числа

Мы можем использовать функцию Number(value), чтобы явно преобразовать value к числу:

 
 
let str = "123";
alert(typeof str); // string

let num = Number(str); // становится числом 123

alert(typeof num); // number

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

Если строка не может быть явно приведена к числу, то результатом преобразования будет NaN. Например:

 
 
let age = Number("Любая строка вместо числа");

alert(age); // NaN, преобразование не удалось

Правила численного преобразования:

ЗначениеПреобразуется в…
undefinedNaN
null0
true / false1 / 0
stringПробельные символы (пробелы, знаки табуляции \t, знаки новой строки \n и т. п.) по краям обрезаются. Далее, если остаётся пустая строка, то получаем 0, иначе из непустой строки «считывается» число. При ошибке результат NaN.

Примеры:

 
 
alert( Number("   123   ") ); // 123
alert( Number("123z") );      // NaN (ошибка чтения числа на месте символа "z")
alert( Number(true) );        // 1
alert( Number(false) );       // 0

Учтите, что null и undefined ведут себя по-разному. Так, null становится нулём, тогда как undefined приводится к NaN.

Большинство математических операторов также производит данное преобразование, как мы увидим в следующей главе.

Логическое преобразование

Логическое преобразование самое простое.

Происходит в логических операциях (позже мы познакомимся с условными проверками и подобными конструкциями), но также может быть выполнено явно с помощью функции Boolean(value).

Правило преобразования:

  • Значения, которые интуитивно «пустые», вроде 0, пустой строки, nullundefined и NaN, становятся false.
  • Все остальные значения становятся true.

Например:

 
 
alert( Boolean(1) ); // true
alert( Boolean(0) ); // false

alert( Boolean("Привет!") ); // true
alert( Boolean("") ); // false
Заметим, что строчка с нулём "0" — это true

Некоторые языки (к примеру, PHP) воспринимают строку "0" как false. Но в JavaScript, если строка не пустая, то она всегда true.

 
 
alert( Boolean("0") ); // true
alert( Boolean(" ") ); // пробел это тоже true (любая непустая строка это true)

 

Приведение к числу, унарный +

Плюс + существует в двух формах: бинарной, которую мы использовали выше, и унарной.

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

Например:

 
 
// Не влияет на числа
let x = 1;
alert( +x ); // 1

let y = -2;
alert( +y ); // -2

// Преобразует не числа в числа
alert( +true ); // 1
alert( +"" );   // 0

На самом деле это то же самое, что и Number(...), только короче.

Необходимость преобразовывать строки в числа возникает очень часто. Например, обычно значения полей HTML-формы — это строки. А что, если их нужно, к примеру, сложить?

Бинарный плюс сложит их как строки:

 
 
let apples = "2";
let oranges = "3";

alert( apples + oranges ); // "23", так как бинарный плюс объединяет строки

Поэтому используем унарный плюс, чтобы преобразовать к числу:

 
 
let apples = "2";
let oranges = "3";

// оба операнда предварительно преобразованы в числа
alert( +apples + +oranges ); // 5

// более длинный вариант
// alert( Number(apples) + Number(oranges) ); // 5

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

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

Сокращённая арифметика с присваиванием

 

Часто нужно применить оператор к переменной и сохранить результат в ней же.

Например:

let n = 2;
n = n + 5;
n = n * 2;

Эту запись можно укоротить при помощи совмещённых операторов += и *=:

 
 
let n = 2;
n += 5; // теперь n = 7 (работает как n = n + 5)
n *= 2; // теперь n = 14 (работает как n = n * 2)

alert( n ); // 14

Подобные краткие формы записи существуют для всех арифметических и побитовых операторов: /=-= и так далее.

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

 
 
let n = 2;

n *= 3 + 5;

alert( n ); // 16  (сначала выполнится правая часть, выражение идентично n *= 8)

Инкремент/декремент

Одной из наиболее частых числовых операций является увеличение или уменьшение на единицу.

Для этого существуют даже специальные операторы:

  • Инкремент ++ увеличивает переменную на 1:

     
     
    let counter = 2;
    counter++;        // работает как counter = counter + 1, просто запись короче
    alert( counter ); // 3
  • Декремент -- уменьшает переменную на 1:

     
     
    let counter = 2;
    counter--;        // работает как counter = counter - 1, просто запись короче
    alert( counter ); // 1

Условное ветвление: if, '?'

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

Для этого мы можем использовать инструкцию if и условный оператор ?, который также называют оператором «вопросительный знак».

Инструкция «if»

Инструкция if(...) вычисляет условие в скобках и, если результат true, то выполняет блок кода.

Например:

 
 
let year = prompt('В каком году была опубликована спецификация ECMAScript-2015?', '');

if (year == 2015) alert( 'Вы правы!' );

В примере выше, условие – это простая проверка на равенство (year == 2015), но оно может быть и гораздо более сложным.

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

if (year == 2015) {
  alert( "Правильно!" );
  alert( "Вы такой умный!" );
}

Мы рекомендуем использовать фигурные скобки {} всегда, когда вы используете инструкцию if, даже если выполняется только одна команда. Это улучшает читаемость кода.

Преобразование к логическому типу

Инструкция if (…) вычисляет выражение в скобках и преобразует результат к логическому типу.

Давайте вспомним правила преобразования типов из главы Преобразование типов:

  • Число 0, пустая строка ""nullundefined и NaN становятся false. Из-за этого их называют «ложными» («falsy») значениями.
  • Остальные значения становятся true, поэтому их называют «правдивыми» («truthy»).

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

if (0) { // 0 is falsy
  ...
}

…а при таком – выполнится всегда:

if (1) { // 1 is truthy
  ...
}

Мы также можем передать заранее вычисленное в переменной логическое значение в if, например так:

let condition = (year == 2015); // преобразуется к true или false

if (condition) {
  ...
}

Блок «else»

Инструкция if может содержать необязательный блок «else» («иначе»). Он выполняется, когда условие ложно.

Например:

 
 
let year = prompt('В каком году была опубликована спецификация ECMAScript-2015?', '');

if (year == 2015) {
  alert( 'Да вы знаток!' );
} else {
  alert( 'А вот и неправильно!' ); // любое значение, кроме 2015
}

Несколько условий: «else if»

Иногда нужно проверить несколько вариантов условия. Для этого используется блок else if.

Например:

 
 
let year = prompt('В каком году была опубликована спецификация ECMAScript-2015?', '');

if (year < 2015) {
  alert( 'Это слишком рано...' );
} else if (year > 2015) {
  alert( 'Это поздновато' );
} else {
  alert( 'Верно!' );
}

В приведённом выше коде JavaScript сначала проверит year < 2015. Если это неверно, он переходит к следующему условию year > 2015. Если оно тоже ложно, тогда сработает последний alert.

Блоков else if может быть и больше. Присутствие блока else не является обязательным.

Условный оператор „?“

Иногда нам нужно определить переменную в зависимости от условия.

Например:

 
 
let accessAllowed;
let age = prompt('Сколько вам лет?', '');

if (age > 18) {
  accessAllowed = true;
} else {
  accessAllowed = false;
}

alert(accessAllowed);

Так называемый «условный» оператор «вопросительный знак» позволяет нам сделать это более коротким и простым способом.

Оператор представлен знаком вопроса ?. Его также называют «тернарный», так как этот оператор, единственный в своём роде, имеет три аргумента.

Синтаксис:

let result = условие ? значение1 : значение2;

Сначала вычисляется условие: если оно истинно, тогда возвращается значение1, в противном случае – значение2.

Например:

let accessAllowed = (age > 18) ? true : false;

Технически, мы можем опустить круглые скобки вокруг age > 18. Оператор вопросительного знака имеет низкий приоритет, поэтому он выполняется после сравнения >.

Этот пример будет делать то же самое, что и предыдущий:

// оператор сравнения "age > 18" выполняется первым в любом случае
// (нет необходимости заключать его в скобки)
let accessAllowed = age > 18 ? true : false;

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

На заметку:

В примере выше вы можете избежать использования оператора вопросительного знака ?, т.к. сравнение само по себе уже возвращает true/false:

// то же самое
let accessAllowed = age > 18;

Несколько операторов „?“

Последовательность операторов вопросительного знака ? позволяет вернуть значение, которое зависит от более чем одного условия.

Например:

 
 
let age = prompt('Возраст?', 18);

let message = (age < 3) ? 'Здравствуй, малыш!' :
  (age < 18) ? 'Привет!' :
  (age < 100) ? 'Здравствуйте!' :
  'Какой необычный возраст!';

alert( message );

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

  1. Первый знак вопроса проверяет age < 3.
  2. Если верно – возвращает 'Здравствуй, малыш!'. В противном случае, проверяет выражение после двоеточия „:“, вычисляет age < 18.
  3. Если это верно – возвращает 'Привет!'. В противном случае, проверяет выражение после следующего двоеточия „:“, вычисляет age < 100.
  4. Если это верно – возвращает 'Здравствуйте!'. В противном случае, возвращает выражение после последнего двоеточия – 'Какой необычный возраст!'.

Вот как это выглядит при использовании if..else:

if (age < 3) {
  message = 'Здравствуй, малыш!';
} else if (age < 18) {
  message = 'Привет!';
} else if (age < 100) {
  message = 'Здравствуйте!';
} else {
  message = 'Какой необычный возраст!';
}

switch case

Конструкция switch заменяет собой сразу несколько if.

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

Синтаксис

Конструкция switch имеет один или более блок case и необязательный блок default.

Выглядит она так:

switch(x) {
  case 'value1':  // if (x === 'value1')
    ...
    [break]

  case 'value2':  // if (x === 'value2')
    ...
    [break]

  default:
    ...
    [break]
}
  • Переменная x проверяется на строгое равенство первому значению value1, затем второму value2 и так далее.
  • Если соответствие установлено – switch начинает выполняться от соответствующей директивы case и далее, до ближайшего break (или до конца switch).
  • Если ни один case не совпал – выполняется (если есть) вариант default.

Пример работы

Пример использования switch (сработавший код выделен):

 
 
let a = 2 + 2;

switch (a) {
  case 3:
    alert( 'Маловато' );
    break;
  case 4:
    alert( 'В точку!' );
    break;
  case 5:
    alert( 'Перебор' );
    break;
  default:
    alert( "Нет таких значений" );
}

Здесь оператор switch последовательно сравнит a со всеми вариантами из case.

Сначала 3, затем – так как нет совпадения – 4. Совпадение найдено, будет выполнен этот вариант, со строки alert( 'В точку!' ) и далее, до ближайшего break, который прервёт выполнение.

Если break нет, то выполнение пойдёт ниже по следующим case, при этом остальные проверки игнорируются.

Пример без break:

 
 
let a = 2 + 2;

switch (a) {
  case 3:
    alert( 'Маловато' );
  case 4:
    alert( 'В точку!' );
  case 5:
    alert( 'Перебор' );
  default:
    alert( "Нет таких значений" );
}

Задание:

  1. Создайте страницу, которая спрашивает имя у пользователя и выводит его.
  2. Используя конструкцию if..else, напишите код, который получает число через prompt, а затем выводит в alert:

    • 1, если значение больше нуля,
    • -1, если значение меньше нуля,
    • 0, если значение равно нулю.

    Предполагается, что пользователь вводит только числа.