Циклы в JavaScript

Циклы в JavaScript
Содержание:
  1. Назначение и виды циклов
  2. Цикл for
  3. Цикл while
  4. Цикл do...while
  5. Цикл for...in
  6. Инструкции break и continue
  7. Цикл for...of (новинка в ES6)
  8. Задачи по циклам
  9. Комментарии

Назначение и виды циклов

Циклы – это простой способ для многократного выполнения одних и тех же действий (кода).

При этом однократное выполнения кода в цикле называется итерацией.

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

Цикл for

Данный цикл в основном используется когда известно точное количество повторений. Этот цикл ещё называют циклом со счётчиком.

Синтаксис цикла «for»:

JavaScript
for (инициализация; условие; финальное выражение) {
  /* тело цикла */
}
Алгоритм работы цикла for в JavaScript

Основные части конструкции цикла «for»:

  • инициализация - это выражение, которое выполняется один раз перед выполнением цикла; обычно используется для инициализации счётчика;
  • условие - это выражение, истинность которого проверяется перед каждой итерацией; если выражение вычисляется как истина, то выполняется итерация; в противном случае цикл «for» завершает работу;
  • финальное выражение - это выражение, которое выполняется в конце каждой итерации; обычно используется для изменения счетчика;
  • тело цикла - инструкции, выполнение которых нужно повторять.

Рассмотрим пример цикла, который выведет в консоль числа от 1 до 8:

JavaScript
// цикл «for» от 1 до 8, с шагом 1
for (var i = 1; i <= 8; i++) {
  console.log(i);
}

В этом примере:

  • инициализация: var i = 1 (объявление переменной i и присвоение ей значения 1);
  • условие выполнения цикла: i <= 8 (пока значение переменной i меньше или равно 8);
  • финальное выражение, которое нужно выполнять в конце каждой итерации: i++ (увеличение значение переменной i на 1);
  • инструкция, которую нужно выполнять: console.log(i) (выведение значения счётчика в консоль).

При этом если тело цикла состоит из одной инструкции, то её можно не заключать в фигурные скобки.

Таким образом, пример, приведённый выше, можно записать ещё так:

JavaScript
// цикл «for» от 1 до 8, с шагом 1
for (var i = 1; i <= 8; i++) console.log(i);

Необязательные части цикла «for».

В «for» все части цикла являются не обязательными.

Например, можно пропустить выражение инициализации:

JavaScript
var i = 1;
// цикл «for»
for (; i <= 8; i++) {
  console.log(i);
}

В этом случае инициализацию переменной можно вынести за пределы цикла.

Условие в «for» тоже является не обязательным. Без условия цикл будет выполняться бесконечное количество раз. В этом случае чтобы его прервать (выйти из цикла) необходимо использовать инструкцию break.

JavaScript
// цикл «for»
for (var i = 1; ; i++) {
  if (i >= 8) { // условие прерывания цикла
    break;
  }
  console.log(i);
}

Финальное выражение в «for» также является не обязательным. Счётчик цикла в этом случае можно, например, изменять в теле.

JavaScript
// цикл «for»
for (var i = 1; i <= 8; ) {
  console.log(i);
  i++; // увеличение счетчика на 1
}

В «for» можно вообще опустить 3 выражения (бесконечный цикл):

JavaScript
var i = 1;
// цикл «for»
for (;;) {
  if (i >= 8) {
    break;
  }
  console.log(i);
  i++;
}

Кроме этого, в качестве тела цикла «for» можно использовать пустое выражение (;). Это используется, когда вам не нужно выполнять ни одной инструкции.

Например:

JavaScript
var
  arrA = [8, 12, 24],
  arrB = [];
for (i = 0; i < arrA.length; arrB[i] = arrA[i++] / 2) ;
console.log(arrB); // [4, 6, 12]

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

JavaScript
// сумма чисел в массиве
var arr = [2, 7, 3];
for (var i = 0, length = arr.length, sum = 0; i < length; sum += arr[i++]) /* пустое выражение */ ;
// выведем сумму чисел в консоль:
console.log(sum); // 12

Пример использования цикла «for» для перебора элементов массива:

JavaScript
var arr = ["a", "b", "c"]; // массив
for (var i = 0, length = arr.length; i < length; i++) {
  console.log(arr[i]);
}

Пример, в котором выведем таблицу умножения в консоль. Для реализации этого примера будем использовать вложенные циклы.

Пример на JavaScript - Вывод таблицы умножения в консоль с использованием вложенных циклов
JavaScript
var output = '';
for (var i = 1; i <= 9; i++) {
  for (var j = 1; j <= 9; j++) {
    output += ' ' + i * j;
    if (i * j < 10) {
      output += ' ';
    }
  }
  console.log(output);
  output = '';
}

Цикл называется вложенным, если он находится в теле другого цикла.

Цикл while

Данный цикл предназначен для многократного выполнения одних и тех же инструкций до тех пор, пока истинно некоторое условие. Цикл «while» в основном используется, когда количество повторений заранее не известно.

JavaScript
while (условие) {
  /* тело цикла */
}
Алгоритм работы цикла while в JavaScript

Истинность условия проверяется перед каждым выполнением. Если перед первой итерацией условие ложно, то цикл не выполнится ни разу.

Пример, в котором выведем в консоль чётные числа в диапазоне от 1 до 8:

JavaScript
// объявим переменную а и присвоим ей значение 0
let a = 0;
//цикл while с условием a <= 8
while (a <= 8) {
  // увеличим значение переменной a на 1
  a++;
  // если число нечётное (остаток от деления на 2 не равен 0), то...
  if (a % 2 !== 0) {
    // пропустим дальнейшее выполнение текущей итерации и перейдём к следующей
    continue;
  }
  // выведем значение переменной a в консоль
  console.log(a);
}

Цикл do...while

Цикл «do...while», также как и цикл «while», выполняет одни и те же инструкции до тех пор, пока указанное условие истинно. Но в отличие от «while» в «do...while» условие проверяется после выполнения инструкций. Поэтому цикл «do...while» в любом случае выполнится не меньше одного раза, даже если условие изначально ложно.

Алгоритм работы цикла do...while в JavaScript
JavaScript
do {
  /* тело цикла */
} while (условие)

Пример, в котором выведем в консоль сумму чисел, которые будем запрашивать у пользователя с помощью функции prompt:

JavaScript
// num – переменная для хранения числа, введённого пользователем
// sum – переменная для хранения суммы чисел
let num, sum = 0;
// цикл «do...while»
do {
  // запросим у пользователя данные и приведём их к числу
  num = +prompt ('Введите число', '');
  // если то, что ввёл пользователь после приведения является числом, то...
  if (num) {
    // прибавим к сумме число, введённое пользователем
    sum += num;
  }
// если num приводится к истине, то выполняем ещё итерацию
} while (num);

console.log(sum);

Цикл for...in

Цикл «for...in» предназначен для перебора перечисляемых имён свойств объекта. В JavaScript свойство является перечисляемым, если его внутренний флаг [[Enumerable]] равен true.

Свойства объекта, которые не относятся к перечисляемым, в цикле не участвуют.

Например, объект (массив) созданный с использованием функции-конструктора Array или его литеральной записи имеет не перечисляемые свойства от Array.prototype и Object.prototype, такие как indexOf(), some(), toString() и др. Они не будут участвовать в цикле.

JavaScript
/* цикл для перебора всех перечисляемых свойств объекта
    - key – переменная, в которую будет помещаться имя свойства объекта
    - object – объект, свойства которого нужно перебрать */
for (key in object) {
  /* тело цикла */
}

Переберём свойства объекта, созданного с помощью литеральной записи:

JavaScript
let car = {
  manufacturer: 'Ford',
  model: 'Fiesta',
  color: 'black'
};
for (let propName in car) {
  // propName – имя свойства
  // car[propName] – значение свойства
  console.log(propName + ' = ' + car[propName]);
}
// в консоль будет выведено: manufacturer = Ford, model = Fiesta, color = black

Кроме этого, следует отметить, что цикл for...in проходит не только по перечисляемых свойствам этого объекта, но и по наследуемым.

JavaScript
let item = {
  a: 1,
  b: 2
}
let newItem = Object.create(item);
newItem.c = 3;
newItem.d = 4;
for (let propName in newItem) {
  console.log(propName);
}
// в консоли будет выведено: c, d, a, b

Если вам наследуемые свойства не нужно учитывать, то их можно пропустить:

JavaScript
for (let propName in newItem) {
  // переходим к следующей итерации, если текущее свойство не принадлежит этому объекту
  if(!newItem.hasOwnProperty(propName)) {
    continue;
  }
  console.log(propName);
}
// в консоли будет выведено: c, d

Использование цикла for... in для перебора массива. В массиве свойствами являются числовые индексы.

JavaScript
// массив
var arr = ["Rock", "Jazz", "Classical", "Hip Hop"];
// перебор массива с помощью цикла for in
for (let index in arr) {
  // index - индекс элемента массива
  // arr[index] – значение элемента
  console.log(arr[index]);
}
// в результате в консоль будет выведено: "Rock", "Jazz", "Classical", "Hip Hop"

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

При использовании цикла for…in стоит обратить внимание на то, что если вы к массиву добавили свои пользовательские свойства, то он по ним тоже пройдётся:

JavaScript
var arr = [5, 7, -3];
arr.sum = 2;
for (var key in arr) {
  console.log(arr[key]);
}
// в консоль будет выведено 5, 7, -3, 2

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

Использование цикла for…in для перебора символов в строке:

JavaScript
var str = 'Метод';
for (var key in str) {
  console.log(str[key]);
}
// М, е, т, о, д

Инструкции break и continue

Внутри тела цикла можно использовать специальные инструкции: break и continue.

Инструкция «break» предназначена для прекращения выполнения текущего цикла. Другими словами, она осуществляет выход и передачу управления инструкции, идущей после этого цикла.

Пример, в котором завершим цикл по перебору элементов массива, если его текущий элемент не будет являться числом:

JavaScript
// массив
var arr = [5, 3, "a", 4, "b", 16];
// цикл «for» для перебора массива arr
for (var i = 0, length = arr.length; i < length; i++) {
  // если текущий элемент массива не является числом, то...
  if (typeof arr[i] !== 'number') {
    // прерываем выполнение цикла
    break;
  }
  // выводим текущий элемент массива в консоль
  console.log(arr[i]);
}
// в результате в консоль будет выведено: 5, 3

Инструкция «continue» предназначена для прекращения дальнейшего выполнения кода и перехода к следующей итерации цикла.

Пример, в котором найдём в слове «программирование» символы «а» и «о», и выведем их позиции в консоль:

JavaScript
// строка
var str = 'программирование';
// цикл "for" для перебора символов строки
for (var i = 0, length = str.length; i < length; i++) {
  // если текущий символ не равен а и о, то...
  if (str[i] !== 'а' && str[i] !== 'о') {
    // прекращаем выполнение текущей итерации и переходим к следующей
    continue;
  }
  // выведем в консоль сам символ и его индекс
  console.log(i + ' => ' + str[i]);
}
// данный цикл выведет в консоль: 2 => "о", 5 => "а", 10 => "о", 12 => "а"

Метки для break и continue

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

JavaScript
someLabel: while (условие) {
  // текло цикла
}

Далее после оператора break или continue необходимо указать эту метку:

JavaScript
someLabel: while (условие) {
  if (условие) {
    break someLabel;
  }
}

Вызов break someLabel приведёт к переходу в конец цикла, перед которым данная метка указана.

Если метка используется с ключевым словом continue, то в этом случае выполнение этого действия приведёт к немедленному переходу к следующей итерации цикла, перед которым данная метка указана.

В коде с одиночным циклом использование метки не даст никакого результата. Её есть смысл использовать только когда вам нужно выйти сразу из нескольких циклов.

Пример, в котором выйдем сразу из 2 циклов, когда произведение значений переменных-счётчиков даст число большее 10.

JavaScript
// обозначим внешний цикл, используя метку outer
outer: for (var i = 2; i < 5; i++) {
  // вложенный цикл
  for (var j = 2; j < 5; j++) {
    // если условие выполняется, то прерываем работу и переходим к концу цикла с меткой outer
    if (i * j > 10) break outer;
    // выведем в консоль
    console.log(i + ' * ' + j + ' = ' + i * j);
  }
}
// в консоль будет выведено: 2 * 2 = 4, 2 * 3 = 6, 2 * 4 = 8, 3 * 2 = 6, 3 * 3 = 9

Кроме этого, операторы break и continue нельзя использовать в выражениях тернарных операторов.

Цикл for...of (новинка в ES6)

Цикл for...of появился в стандарте ES6. Предназначен он для перебора итерируемых объектов, т.е. объектов, в которых реализован метод Symbol.iterator. Этот метод ещё называют итератором. Именно его и использует цикл for...of для перебора объектов.

Метод Symbol.iterator имеется у String, Array, Map, Set, arguments, NodeList и других объектов.

Пример использование цикла for...of для посимвольного перебора строки:

JavaScript
// переменная, содержащая строку
let str = 'Новый';
// посимвольный перебор строки
for (let char of str) {
  console.log(char);
}
// в консоль будет выведено: "Н", "о", "в", "ы", "й"

Пример использование цикла for...of для перебора коллекции DOM-элементов:

JavaScript
let elements = document.querySelectorAll('p');
for (let element of elements) {
  console.log(element);
}

Пример использование цикла for...of для перебора массива:

JavaScript
// массив
let superHeroes = ['Iron Man', 'Thor', 'Hulk'];
// перебор массива
for (let value of superHeroes) {
  console.log(value);
}
// в консоль будет выведено: "Iron Man", "Thor", "Hulk"

Чем цикл for...of отличается от for...in

Первое отличие цикла for...of от for...in заключается в том, что он может применяться только для итерируемым объектов, т.е. объектов, в которых реализован итератор (Symbol.iterator). Цикл for...in итератор не использует. Он предназначен для перебора любых объектов.

Второе отличие заключается в том, что цикл for...of перебирает объект так, как это определено в итераторе. Например, в Array итератор реализован так, что цикл for...of пройдёт только по значениям в массиве и не будет включать в перебор другие (не индексные) свойства. Цикл for...in организован по-другому, он перебирает все перечисляемые свойства (имена ключей) объекта, в том числе и наследуемые.

Рассмотрим эти отличия. Для этого возьмём предыдущий пример и добавим к нему пользовательское свойство, например, hero и установим ему значение 'Wasp'.

JavaScript
let superHeroes = ['Iron Man', 'Thor', 'Hulk'];
superHeroes.hero = 'Wasp';

При использовании for...of он переберёт все значения этого массива:

JavaScript
// цикл for...of
for (let value of superHeroes) {
  console.log(value);
}
// в консоль будет выведено: "Iron Man", "Thor", "Hulk"

При использовании for...in он переберёт все перечисляемые имена ключей этого объекта:

JavaScript
// цикл for...in
for (let key in superHeroes) {
  console.log(key);
}
// в консоль будет выведено: 0, 1, 2, "hero"

Чтобы получить значение ключа по его имени можно воспользоваться квадратными скобками:

JavaScript
// цикл for...in
for (let key in superHeroes) {
  console.log(superHeroes[key]);
}
// в консоль будет выведено: "Iron Man", "Thor", "Hulk", "Wasp"

Самостоятельное создание итератора для объекта

Рассмотрим ещё один пример. В этом примере мы самостоятельно определим как должен итерироваться объект. Для этого создадим объект и определим ему итератор.

Создание итератора начинается с добавления к объекту специального метода. Этот метод необходимо спроектировать так, чтобы он возвращал значения последовательно (одно за другим). Название методу согласно стандарту необходимо определить с помощью символа Symbol.iterator. Итератор должен возвращать всего один метод next(). Этот метод в свою очередь тоже должен возвращать объект, состоящий из 2 свойств: value и done. Ключ done - булевый. Он определяет есть ли ещё значения в последовательности (false - да, true - нет). Ключ value должен содержать следующее значение последовательности.

JavaScript
let car = {
  color: 'black',
  brand: 'Ford',
  // создадим итератор, используя символ
  [Symbol.iterator]() {
    // получим имена перечисляемых свойств объекта
    const keys = Object.keys(this);
    // создадим переменную (текущий индекс последовательности)
    let index = 0;
    return {
      next() {
        let done = index >= keys.length;
        let value = done ? undefined : keys[index++];
        return {
          value,
          done
        }
      }
    }
  }
}

for (let key of car) {
  console.log(key + ' => ' + car[key]);
}
// в консоль будет выведено: color => "black", brand => "Ford"

Задачи по циклам

1. Написать с помощью цикла while «переворот» числа. Другими словами, нужно создать новое число, у которого цифры шли бы в обратном порядке (например: 472 -> 274).

Решение

2. Найти самую большую цифру в целом числе.

Решение

3. Вычислить сумму первой и последней цифр целого числа.

Решение

Комментарии: 18

Will
Will

Добрый день, спасибо за труд. Недавно изучаю JS.

Асинхронно ф. potok1() пишет в СКЛ табл IN, затем

мне надо постоянно эту табл IN читать и извлекать записи из нее придумал так называемый вечный цикл (while(true){)

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

мозг перестроить от VB/VBS/VBA в JS парадигму. Если не сложно посоветуйте как решать подобные задачи.

Еще раз спасибо за сайт и возможный ответ.

...

(async function potok1() { //из Телеграма 
    let   http_cmd = `${bot_api_server}/getUpdates`;
    while (true){
        const response = await axios.get(http_cmd);
        const updates = response.data.result;
        const SQL = 'insert into `IN` (UPDATE_ID, TYPE, WHAT) values (?, ?, ?)';    
        updates.forEach((update) => {
            console.log('update_id='+update.update_id);
            db_.run(SQL, update.update_id, Object.keys(update)[1], JSON.stringify(update));
            axios.get(`${bot_api_server}/getUpdates?offset=${update.update_id+1}`);
            offset=update.update_id
        })
        offset=offset+1;
        await sleep(50);
    }
    }
)();
let rs_;
let SQL=`select * from [IN] where RC=0`;
while(true){
       rs_= await db_.all(SQL); 
       if (!rs_.length) {await sleep(50)}  
       for (let rsItem of rs_)  {
          ... 
           await db_.run(`update [IN] set RC=1 where ID=?`, rsItem[`ID`]);
       } 
}
Emma
Emma

Здравствуйте! Спасибо за статью!

Сможете , пожалуйста , помочь с задачей?

Я поняла как решить.

Необходимо напечатать на экране с помощью alert прямоугольник, состоящий из символа, который запрошен у пользователя. Прямоугольник должен иметь 20 символов в длину и 7 символов в высоту.

Пример:

Введите символ:

&

Указания:

Для решения данного упражнения использовать вложенные циклы.

Спасибо заранее!

Александр Мальцев
Александр Мальцев

Добрый день! Пожалуйста!

Если правильно понял условия задачи, то так:
const symbol = prompt('Введите символ, с помощью которого нужно нарисовать прямоугольник?');
const width = 20;
const height = 7;
let text = '';

for (let h = 1; h <= height; h++) {
  for (let w = 1; w <= width; w++) {
    text += symbol;
  }
  text += '\n';
}

alert(text);
DeKn
DeKn

Здравствуйте! В примере про создание итератора, в конце почему то используется цикл for...in. Спасибо. У вас отличный учебник по JS, обучаюсь по нему.

Александр Мальцев
Александр Мальцев

Добрый день! Благодарю за отзыв. Рад что учебник нравится. Спасибо, поправил недочет.

Татьяна
Татьяна
Александр, как написать шаг (неизвестно), но не 1?
function withStep(num, step){

}

withStep(10, 3) === 22 (1 + 4 + 7 + 10);
withStep(0) === 0;
withStep(5, 3) === 5 (1 + 4);
withStep(18, 10) === 12 (1 + 11);
Татьяна
Татьяна
Уже написала, спасибо за статью)
Татьяна
Татьяна
Александр, как написать арифметическую прогрессию, используя цикл For,
например 1 + 2 + 3 = 6
getSweets(3) === 6 (1 + 2 + 3);
getSweets(0) === 0 нет гостей - нет конфет;
getSweets(5) === 15 (1 + 2 + 3 + 4 + 5);

function getSweets(numberOfGuests) {

}
Заранее благодарю.
Александр Мальцев
Александр Мальцев
Например, так:
function getSweets(numberOfGuests) {
  let sum = 0;
  for (let i = 0; i < numberOfGuests; sum += ++i);
  return sum;
}
Татьяна
Татьяна
Спасибо) работает.
Evgen
Evgen
Подскажите еще по поводу этого вашего примера:
let item = {
  a: 1,
  b: 2
}
let newItem = Object.create(item);
newItem.c = 3;
newItem.d = 4;
for (let propName in newItem) {
  console.log(propName);
}
// в консоли будет выведено: a, b, c, d
В консоле имена свойств выводятся не по порядку, а так: c, d, a, b.
Вопрос такой: как сделать так, чтобы они были выведены по порядку. С помощью метода .sort() у меня не получается. Спасибо!
Александр Мальцев
Александр Мальцев
В этом случае можно сначала добавить их в массив, а затем используя sort отсортировать их. После этого уже вывести их, например, в консоль:
let item = {
  a: 1,
  b: 2
}
let newItem = Object.create(item);
newItem.c = 3;
newItem.d = 4;

let arrPropName = [];
for (let propName in newItem) {
  arrPropName.push(propName);
}
arrPropName.sort();
console.log(arrPropName.join(', '));
Evgen
Evgen
Пример с do...while тоже, как по мне, не работает…
Во-первых, «Uncaught ReferenceError: data is not defined».
Во-вторых, console.log в этом примере отсутствует. Исходя их этого, туда ничего и не выведется.
Может быть, нужно так:

// num – переменная для хранения числа, введённого пользователем
// sum – переменная для хранения суммы чисел
var num, sum = 0;
// цикл «do...while»
do {
  // запросим у пользователя данные и приведём их к числу
  num = +prompt ('Введите число', '');
  // если то, что ввёл пользователь после приведения является числом, то...
  if (num) {
    // прибавим к сумме число, введённое пользователем
    sum += num;
  }
// если num приводится к истине, то выполняем ещё итерацию
} while (num); 
console.log(sum)
Александр Мальцев
Александр Мальцев
Спасибо! Пример, поправил.
Evgen
Evgen
Добрый день! Пример для цикла while не работает. Выводит просто «1», а не «чётные числа в диапазоне от 1 до 8»
Александр Мальцев
Александр Мальцев
Здравствуйте! Спасибо! Пример, поправил.
Viktoriia
Viktoriia
Добрый день,
Что-то вы в этом примере напутали :)

//строка
var str = 'программирование';
// цикл "for" для перебора символов строки 
for (var i = 0, length = str.length; i < length; i++) {
  // если текущий символ не равен а и о, то...
  if (arr[i] !== 'а' && arr[i] !== 'о') {
    // прекращаем выполнение текущей итерации и переходим к следующей
    continue;
  }
  // выводим в консоль порядковый номер символа
  console.log(arr[i]);
}
// данный цикл выведет в консоль: 3, 6, 11, 13  
Вы работаете в цикле с arr (а должны с str). А также, неверен результат цикла в консоле. так как результатом будут не индексы букв, а сами буквы «а» и «о».
Александр Мальцев
Александр Мальцев
Привет!
Да, есть такое :)
Спасибо! Код изменил.