Ни одна
сколь-нибудь серьезная программа на JavaScript не обходится без
циклов. Что такое циклы? Представьте, что вам необходимо вычислить вот такую
вот сумму:
Расписывать все
это через тысячу слагаемых не очень то удобно. И к тому же число слагаемых
может зависеть от значения переменной и быть неопределенным. В таких задачах
без циклов не обойтись. Представим сначала эту задачу в виде вот такой
блок-схемы.
Здесь мы сначала
инициализируем переменные S=0 и i=1, а дальше
идет такая конструкция. Сначала проверяем условие, если i <=1000, то к
предыдущему значению S прибавляем текущее слагаемое 1/i, а затем, i увеличиваем на
1. И снова переходим на проверку: является ли i <= 1000. Если
так, то вычисление суммы продолжается, а иначе завершаем работу алгоритма.
Оператор цикла while
Эта блок схема
показывает принцип работы цикла и отсюда хорошо видно, что цикл состоит из двух
составляющих: условия цикла и тела цикла, то есть, операторов, которые
выполняются внутри цикла. В частности, такую конструкцию можно реализовать с
помощью оператора цикла while, по следующему синтаксису:
while(<выражение>)
{
[тело
цикла]
}
И программа
будет выглядеть так:
let S=0, i=1;
while(i <= 1000) {
S += 1/i;
++i;
}
console.log(S);
В качестве
выражения в цикле while можно писать все те же самые условия,
что и в условном операторе if. Например, можно вычислять сумму S пока либо i<=1000, либо S < 5. Такое
условие запишется так:
while(i <= 1000 && S < 5)
здесь цикл будет
работать пока i<=1000 и S<5 как только
одно из подусловий станет ложным, все составное условие становится ложным и
цикл завершит свою работу.
Рассмотрим еще
один пример. Будем вычислять сумму
и запишем все
вот в такой краткой форме:
let S=0, i=1;
while((S += i++) < 100 );
console.log(S);
Здесь сумма
вычисляется непосредственно внутри выражения, а тело цикла отсутствует – после while стоит точка с
запятой. Так тоже можно делать, но не рекомендуется, т.к. это усложняет
понимание работы программы другими программистами. Лучше все расписывать в
несколько строк.
Оператор цикла for
Самый часто
используемый оператор цикла – это оператор for, который имеет
такой синтаксис:
for(<инициализация
счетчика>;<условие>;<изменение счетчика>) {
[тело цикла]
}
Давайте
перепишем нашу программу подсчета суммы
с помощью цикла for, получим:
let S=0;
for(let i=1;i <= 1000; ++i) S += 1/i;
console.log(S);
Здесь весь цикл
записан буквально в одну строчку, а тело цикла состоит из одного оператора –
подсчета суммы ряда. Именно поэтому здесь не стоят фигурные скобки – для одного
оператора они не обязательны.
Вначале идет
инициализация счетчика let i=1, через точку
с запятой – условие цикла и далее через точку с запятой правило изменения
счетчика: увеличение на 1 на каждой итерации. Такая запись цикла выглядит
гораздо короче и нагляднее, поэтому оператор for так часто
используется на практике.
Вторым примером рассмотрим
задачу вычисления значений линейной функции
Скрипт будет
выглядеть так:
let f, k = 0.5, b = 2;
for(let x=0;x <= 1; x += 0.1) {
f = k*x+b;
console.log(f);
}
Здесь все
достаточно очевидно, только теперь счетчик x у нас меняется
от 0 до 1 с шагом 0,1. Далее идет тело цикла из двух операторов, поэтому они
заключены в фигурные скобки.
Цикл for можно
записывать и в таком виде:
let x=0;
for(;x <= 1; x += 0.1) { ... }
или так:
let x=0;
for(;x <= 1; ) {
f = k*x+b;
console.log(f);
x += 0.1;
}
или, даже так:
let x=0;
for(;;) {
if(x > 1) break;
f = k*x+b;
console.log(f);
x += 0.1;
}
В последнем
случае мы не прописали никакого условия, поэтому цикл for работал бы
вечно. Поэтому в теле цикла добавлена проверка: если x>1, то
выполняется оператор break, который прерывает работу цикла. Забегая
вперед, скажу, что оператор break прерывает работу любого цикла, не
только for.
Оператор цикла do while
Последний
оператор цикла, который мы рассмотрим – это цикл do while. Он имеет следующий
синтаксис:
do {
[тело
цикла]
}
while(<выражение>);
Отличие этого
цикла от двух предыдущих в том, что он сначала выполняет тело цикла и только
потом проверяет условие цикла: если оно истинно, то цикл продолжается, если
ложно, то завершается.
Когда может
использоваться такая конструкция? Например, если пользователь вводит с
клавиатуры некий пароль и мы должны проверить: правильно ли он был введен. Если
правильно, то цикл завершается, иначе просим пользователя ввести пароль
повторно. Такую программу можно реализовать так:
const PSW = "password";
let psw = null;
do {
psw = prompt("Введите пароль", "");
}
while(psw != PSW);
console.log("Вы вошли в систему!");
Вложенные циклы
Итак, мы с вами
рассмотрели три цикла: while, for и do while. Все эти циклы
можно комбинировать друг с другом. То есть, создавать вложенные циклы. Когда
это необходимо? Например, для подсчета вот такой двойной суммы ряда
Программа для ее
вычисления будет выглядеть так:
let S=0, M=10, N=5;
for(let i=1;i <= N; ++i)
for(let j=1; j <= M; ++j)
S += i*j;
console.log("S = " + S);
Мы здесь сначала
пробегаем все значения j от 1 до M при
фиксированном i=1, затем,
значение i увеличивается
на 1, становится 2 и при этом i снова пробегаются значения j от 1 до M. И так пока i не превысит
значение N. То есть,
второй цикл вложен вот в этот первый. И таких вложений можно делать сколько
угодно.
Операторы break и continue
Всеми тремя
циклами можно управлять с помощью двух специальных операторов: break и continue. Об операторе break мы уже говорили
– он прерывает работу любого цикла. Но только одного. Например, здесь при
вложенных циклах:
for(let i=1;i <= N; ++i)
for(let j=1; j <= M; ++j) {
if(j == 5) break;
S += i*j;
}
будет остановлен
только один внутренний цикл и управление будет передано внешнему циклу. Чтобы
прервать оба цикла можно использовать оператор break с меткой вот
так:
all: for(let i=1;i <= N; ++i)
for(let j=1; j <= M; ++j) {
if(j == 5) break all;
S += i*j;
}
Мы здесь явно
указываем внешний цикл с меткой all, который следует прервать. В результате
будут остановлены оба цикла. Здесь следует иметь в виду, что в данном случае
метки применяются именно к операторам циклов. Если метку записать выше или
ниже, она либо не сработает, либо применится к ближайшему циклу, содержащему
оператор break.
Следующий
оператор continue позволяет
пропускать тело цикла и перейти к следующей итерации, не прерывая работу самого
цикла. Например, мы хотим перебрать все целые значения от -5 до 5, исключая
значение 0. Такую программу можно реализовать так:
for(let i=-5;i <= 5; ++i) {
if(i == 0) continue;
console.log("i = " + i);
}
При выполнении
этой программы увидим, что в консоль выведены все значения кроме нуля. Так как
при i=0 срабатывает
условие и выполняется оператор continue. Все что находится после этого
оператора пропускается и цикл продолжается уже со значением i=1.
Оператор continue также можно
использовать с меткой, подобно оператору break.
Вот мы с вами
рассмотрели базовые реализации операторов циклов. Забегая вперед, скажу, что в JavaScript имеются и
другие реализации для циклов, но о них речь пойдет когда возникнет
необходимость в их применении.