Марейн Хавербеке - Выразительный JavaScript
Простая схема прямого порядка исполнения программы:
Условное выполнение
Выполнять инструкции по порядку – не единственная возможность. В качестве альтернативы существует условное выполнение, где мы выбираем из двух возможных путей, основываясь на булевской величине:
Условное выполнение записывается при помощи ключевого слова if. В простом случае нам нужно, чтобы некий код был выполнен, только если выполняется некое условие. К примеру, в предыдущей программе мы можем считать квадрат, только если было введено именно число.
var theNumber = prompt("Выбери число ", "");
if (!isNaN(theNumber))
alert("Твоё число – квадратный корень из " + theNumber * theNumber);
Теперь, введя «сыр», вы не получите вывод.
Ключевое слово if выполняет или пропускает инструкцию, в зависимости от значения булевого выражения. Это выражение записывается после if в скобках, и за ним идёт нужная инструкция.
Функция isNaN – стандартная функция JavaScript, которая возвращает true, только если её аргумент – NaN (не число). Функция Number возвращает NaN, если задать ей строку, которая не представляет собой допустимое число. В результате, условие звучит так: «выполнить, если только theNumber не является не-числом».
Часто нужно написать код не только для случая, когда выражение истинно, но и для случая, когда оно ложно. Путь с вариантами – это вторая стрелочка диаграммы. Ключевое слово else используется вместе с if для создания двух раздельных путей выполнения.
var theNumber = Number(prompt("Выбери число", ""));
if (!isNaN(theNumber))
alert("Твоё число – квадратный корень из " + theNumber * theNumber);
else
alert("Ну ты что число-то не ввёл?");
Если вам нужно больше разных путей, можно использовать несколько пар if/else по цепочке.
var num = Number(prompt("Выбери число", "0"));
if (num < 10)
alert("Маловато");
else if (num < 100)
alert("Нормально");
else
alert("Многовато");
Программа проверяет, действительно ли num меньше 10. Если да – выбирает эту ветку, и показывает «Маловато». Если нет, выбирает другую – на которой ещё один if. Если следующее условие выполняется, значит номер будет между 10 и 100, и выводится «Нормально». Если нет – значит, выполняется последняя ветка.
Последовательность выполнения примерно такая:
Циклы while и do
Представьте программу, выводящую все чётные числа от 0 до 12. Можно записать её так:
console.log(0);
console.log(2);
console.log(4);
console.log(6);
console.log(8);
console.log(10);
console.log(12);
Это работает – но смысл программирования в том, чтобы работать меньше, чем компьютер, а не наоборот. Если б нам понадобились все числа до 1000, это решение было бы неприемлемым. Нам нужна возможность повторения. Этот вид контроля над порядком выполнения называется циклом.
Зацикливание даёт возможность вернуться назад к какой-то инструкции и повторить всё заново с новым состоянием программы. Если скомбинировать это с переменной для подсчёта, можно сделать следующее:
var number = 0;
while (number <= 12) {
console.log(number);
number = number + 2;
}
// → 0
// → 2
// … и т.д.
Инструкция, начинающаяся с ключевого слова while – это цикл. За while следует выражение в скобках, и затем инструкция (тело цикла) – так же, как у if. Цикл выполняет инструкцию, пока выражение выдаёт истинный результат.
В цикле нам нужно выводить значение и прибавлять к нему. Если нам нужно выполнять в цикле несколько инструкций, мы заключаем его в фигурные скобки { }. Фигурные скобки для инструкций – как круглые скобки для выражений. Они группируют их и превращают в единое. Последовательность инструкций, заключённая в фигурные скобки, называется блоком.
Много программистов заключают любое тело цикла в скобки. Они делают это для единообразия, и для того, чтобы не нужно было добавлять и убирать скобки, если приходится изменять количество инструкций в цикле. В книге я не буду писать скобки вокруг единичных инструкций в цикле, так как люблю краткость. Вы можете делать, как угодно.
Переменная number показывает, как переменная может отслеживать прогресс программы. При каждом повторении цикла number увеличивается на 2. Перед каждым повторением оно сравнивается с 12, чтобы понять, сделала ли программа всё, что требовалось.
Для примера более полезной работы мы можем написать программу вычисления 2 в 10 степени. Мы используем две переменные: одну для слежения за результатом, а вторую – для подсчёта количества умножений. Цикл проверяет, достигла ли вторая переменная 10, и затем обновляет обе.
var result = 1;
var counter = 0;
while (counter < 10) {
result = result * 2;
counter = counter + 1;
}
console.log(result);
// → 1024
Можно начинать counter с 1 и проверять его на <=10, но по причинам, которые станут ясны далее, всегда лучше начинать счётчики с 0.
Цикл do похож на цикл while. Отличается только в одном: цикл do всегда выполняет тело хотя бы один раз, а проверяет условие после первого выполнения. Поэтому и тестируемое выражение записывают после тела цикла:
do {
var name = prompt("Who are you?");
} while (!name);
console.log(name);
Эта программа заставляет ввести имя. Она спрашивает его снова и снова, пока не получит что-то кроме пустой строки. Добавление "!" превращает значение в булевское и затем применяет логическое отрицание, а все строки, кроме пустой, преобразуются в булевское true.
Вы, наверно, заметили пробелы перед некоторыми инструкциями. В JavaScript это не обязательно – программа отработает и без них. Даже переводы строк не обязательно делать. Можно написать программу в одну строку. Роль пробелов в блоках – отделять их от остальной программы. В сложном коде, где в блоках встречаются другие блоки, может быть сложно разглядеть, где кончается один и начинается другой. Правильно отделяя их пробелами вы приводите в соответствие внешний вид кода и его блоки. Я люблю отделять каждый блок двумя пробелами, но вкусы различаются – некоторые используют четыре, некоторые – табуляцию. Чем больше пробелов использовать, тем заметнее отступ, но тем быстрее вложенные блоки убегают за правый край экрана.
Циклы for
Много циклов строятся по такому шаблону, как в примере. Создаётся переменная-счётчик, потом идёт цикл while, где проверочное выражение обычно проверяет, не достигли ли мы какой-нибудь границы. В конце тела цикла счётчик обновляется.
Поскольку это такой частый случай, в JavaScript есть вариант покороче, цикл for.
for (var number = 0; number <= 12; number = number + 2)
console.log(number);
// → 0
// → 2
// … и т.д.
Эта программа эквивалентна предыдущей. Только теперь все инструкции, относящиеся к отслеживанию состояния цикла, сгруппированы.
Скобки после for содержат две точки с запятой, разделяя инструкцию на три части. Первая инициализирует цикл, обычно задавая начальное значение переменной. Вторая – выражение проверки необходимости продолжения цикла. Третья – обновляет состояние после каждого прохода. В большинстве случаев такая запись более короткая и понятная, чем while.
Вычисляем 210 при помощи for:
var result = 1;
for (var counter = 0; counter < 10; counter = counter + 1)
result = result * 2;
console.log(result);
// → 1024
Хотя я не писал фигурных скобок, я отделяю тело цикла пробелами.
Выход из цикла
Дождаться, пока условие цикла не станет ложным – не единственный способ закончить цикл. Специальная инструкция break приводит к немедленному выходу из цикла.
В следующем примере мы покидаем цикл, когда находим число, большее 20 и делящееся на 7 без остатка.
for (var current = 20; ; current++) {
if (current % 7 == 0)
break;
}
console.log(current);
// → 21
Конструкция for не имеет проверочной части – поэтому цикл не остановится, пока не сработает инструкция break.
Если вы не укажете эту инструкцию, или случайно напишете условие, которое всегда выполняется, программа зависнет в бесконечном цикле и никогда не закончит работу – обычно это плохо.
Если вы сделаете бесконечный цикл, обычно через несколько секунд среда исполнения предложит вам прервать его. Если нет, вам придётся закрыть закладку, или даже весь браузер.