Операторы циклов for, while, do while

Ни одна сколь-нибудь серьезная программа на 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 имеются и другие реализации для циклов, но о них речь пойдет когда возникнет необходимость в их применении.

Видео по теме