Цикли й ітерація
Цикли пропонують швидкий і легкий спосіб зробити щось кілька разів. Цей розділ Посібника з JavaScript знайомить з різними інструкціями ітерації, доступними в JavaScript.
Цикл можна уявити як комп'ютеризовану версію гри, в якій комусь кажуть зробити X кроків в одному напрямку, а тоді Y кроків у іншому. Наприклад, ідея "зробити п'ять кроків на схід" може бути виражена в циклі отак:
for (let step = 0; step < 5; step++) {
// Спрацьовує 5 разів, причому значення step – від 0 до 4.
console.log("Крок на схід");
}
Є чимало різних видів циклів, але всі вони по суті роблять одне й те ж: повторюють дію певну кількість разів. (Слід мати на увазі, що ця кількість може бути нулем!)
Різні механізми циклів пропонують різні способи визначення початкової й кінцевої точок циклу. Є різні ситуації, котрі легше обробляти за допомогою певного конкретного різновиду циклів.
Інструкції циклів, доступні в JavaScript:
- Інструкція for
- Інструкція do...while
- Інструкція while
- Інструкція з міткою
- Інструкція break
- Інструкція continue
- Інструкція for...in
- Інструкція for...of
Інструкція for
Цикл for
повторюється, поки певна умова не обчислиться в хибність. Цикл JavaScript for
подібний до циклу for
Java та C.
Інструкція for
має наступний вигляд:
for ([initialExpression]; [conditionExpression]; [incrementExpression])
statement;
Коли виконується цикл for
, відбувається наступне:
- Виконується вираз ініціалізації
initialExpression
, якщо він є. Цей вираз зазвичай ініціалізує один чи більше лічильників циклу, але синтаксис дозволяє вираз будь-якої складності. Цей вираз також може оголошувати змінні. - Обчислюється вираз
conditionExpression
. Якщо значенняconditionExpression
– істинне, то інструкції циклу виконуються. Інакше – циклfor
завершується. (Якщо виразconditionExpression
повністю упущений, то робиться припущення, що умова виконана.) - Виконується
statement
. Щоб виконати декілька інструкцій, для їх групування слід використовувати блокову інструкцію ({ }
). - Виконується інструкція оновлення
incrementExpression
, якщо вона присутня. - Виконання переходить до кроку №2.
Приклад
У прикладі нижче функція містить інструкцію for
, котра підраховує кількість обраних варіантів у прокрутному списку (елементі <select>
, що дозволяє вибрати декілька варіантів).
HTML
<form name="selectForm">
<label for="musicTypes"
>Оберіть кілька різновидів музики, а тоді клацніть кнопку нижче:</label
>
<select id="musicTypes" name="musicTypes" multiple>
<option selected>Ритм-енд-блюз</option>
<option>Джаз</option>
<option>Блюз</option>
<option>Нью-ейдж</option>
<option>Класична музика</option>
<option>Опера</option>
</select>
<button id="btn" type="button">Скільки різновидів обрано?</button>
</form>
JavaScript
Тут інструкція for
оголошує змінну i
та ініціалізує її значенням 0
. Вона перевіряє, що i
менша за кількість варіантів у елементі <select>
, виконує наступну інструкцію if
та збільшує i
після кожного проходження тіла циклу.
function countSelected(selectObject) {
let numberSelected = 0;
for (let i = 0; i < selectObject.options.length; i++) {
if (selectObject.options[i].selected) {
numberSelected++;
}
}
return numberSelected;
}
const btn = document.getElementById("btn");
btn.addEventListener("click", () => {
const musicTypes = document.selectForm.musicTypes;
console.log(`Обрано варіантів: ${countSelected(musicTypes)}.`);
});
Інструкція do...while
Інструкція do...while
повторює, поки задана умова не стане хибною.
Інструкція do...while
має наступний вигляд:
do
statement
while (condition);
statement
завжди виконується принаймні один раз до перевірки умови. (Для виконання кількох інструкцій слід використовувати блокову інструкцію ({ }
), аби їх згрупувати.)
Якщо condition
– true
, то інструкція виконується знову. В кінці кожного виконання перевіряється умова. Коли умова стає false
, виконання зупиняється, і далі відбувається перехід до інструкції, що стоїть після do...while
.
Приклад
У наступному прикладі цикл do
виконується принаймні раз, і повторюється, поки i
не перестане бути меншою за 5
.
let i = 0;
do {
i += 1;
console.log(i);
} while (i < 5);
Інструкція while
Інструкція while
виконує інструкції свого тіла, поки задана умова обчислюється в true
. Інструкція while
має наступний вигляд
while (condition)
statement
Якщо condition
стає false
, то statement
усередині циклу зупиняє виконання, далі виконується інструкція після циклу.
Перевірка умови відбувається до виконання statement
у циклі. Якщо умова повертає true
, то statement
виконується, і condition
перевіряється знову. Якщо умова повертає false
, то виконання зупиняється, і контроль виконання передається інструкції, що стоїть після while
.
Для виконання кількох інструкцій слід використовувати блокову інструкцію ({ }
), аби їх згрупувати.
Приклад 1
Наступний цикл while
ітерує, поки n
є меншою за 3
:
let n = 0;
let x = 0;
while (n < 3) {
n++;
x += n;
}
З кожною ітерацією цикл збільшує n
на одиницю і додає нове значення до x
. Таким чином, x
і n
приймають наступні значення:
- Після першого проходження:
n
=1
іx
=1
- Після другого проходження:
n
=2
іx
=3
- Після третього проходження:
n
=3
іx
=6
Після завершення третього проходження умова n < 3
вже не true
, тому цикл завершується.
Приклад 2
Уникайте нескінченних циклів. Слідкуйте, аби умова циклу врешті ставала false
: інакше цикл ніколи не завершиться! Інструкції наступного циклу while
виконуються нескінченно, бо умова ніколи не стає false
:
// Нескінченні цикли - це погано!
while (true) {
console.log("Привіт, світе!");
}
Інструкція з міткою
Мітка
дає інструкції ідентифікатор, що дає змогу звертатися до неї деінде в програмі. Наприклад, можна використати мітку для ідентифікації циклу, а потім використати інструкції break
чи continue
, аби вказати, коли програма повинна перервати цей цикл чи продовжити його виконання.
Синтаксис інструкції з міткою має наступний вигляд:
label:
statement
Значення label
може бути будь-яким ідентифікатором JavaScript, що не є зарезервованим словом. statement
, котра ідентифікується міткою, може бути будь-якою інструкцією. Приклади застосування інструкцій з мітками шукайте в прикладах break
і continue
нижче.
Інструкція break
Для завершення циклу чи switch
слід використовувати інструкцію break
окремо, або вкупі з інструкцією, позначеною міткою.
- Коли
break
використовується без мітки, вона негайно завершує найближчий вкладенийwhile
,do-while
,for
абоswitch
, що її оточує, і передає контроль виконання до наступної інструкції. - Коли
break
використовується з міткою, вона завершує вказану інструкцію з міткою.
Синтаксис інструкції break
має такий вигляд:
break;
break label;
- Перша форма синтаксису завершує найглибший вкладений цикл чи
switch
навколо. - Друга форма синтаксису завершує названу інструкцію навколо.
Приклад 1
Наступний приклад ітерує елементи масиву, поки не знайде індекс елемента, чиє значення – theValue
:
for (let i = 0; i < a.length; i++) {
if (a[i] === theValue) {
break;
}
}
Приклад 2: переривання за міткою
let x = 0;
let z = 0;
labelCancelLoops: while (true) {
console.log("Зовнішній цикл:", x);
x += 1;
z = 1;
while (true) {
console.log("Внутрішній цикл:", z);
z += 1;
if (z === 10 && x === 10) {
break labelCancelLoops;
} else if (z === 10) {
break;
}
}
}
Інструкція continue
Інструкція continue
може використовуватися для перезапуску інструкції
while
, do-while
, for
чи label
.
- Коли
continue
використовується без мітки, вона завершує поточну ітерацію інструкціїwhile
,do-while
чиfor
навколо, що має найглибший рівень вкладеності, й продовжує виконання циклу з наступної ітерації. На противагу інструкціїbreak
,continue
не завершує виконання всього циклу. В цикліwhile
вона перестрибує назад до умови. В цикліfor
вона перестрибує доincrement-expression
. - Коли
continue
використовується з міткою, то застосовується до тієї інструкції циклу, яка ідентифікується заданою міткою.
Синтаксис інструкції continue
має наступний вигляд:
continue;
continue label;
Приклад 1
Наступний приклад демонструє цикл while
з інструкцією continue
, що виконується, коли значення i
– 3
. Таким чином, n
приймає значення 1
, 3
, 7
і 12
.
let i = 0;
let n = 0;
while (i < 5) {
i++;
if (i === 3) {
continue;
}
n += i;
console.log(n);
}
// Виводить:
// 1 3 7 12
Якщо закоментувати continue;
, то цикл працюватиме до кінця й виведе 1,3,6,10,15
.
Приклад 2
Інструкція з міткою checkIandJ
містить іншу, позначену міткою checkJ
, інструкцію. Якщо трапилась continue
, то програма завершує поточну ітерацію checkJ
, і починає наступну. Щоразу, коли трапляється continue
, checkJ
повторює виконання, поки її умова не поверне false
. Коли повернено false
, завершується решта checkIandJ
, і checkIandJ
повторює своє виконання, поки її умова не поверне false
. Коли повернено false
, програма продовжується з інструкції, що стоїть після checkIandJ
.
Якби continue
мала мітку checkIandJ
, програма продовжилася б з верху інструкції checkIandJ
.
let i = 0;
let j = 10;
checkIandJ: while (i < 4) {
console.log(i);
i += 1;
checkJ: while (j > 4) {
console.log(j);
j -= 1;
if (j % 2 === 0) {
continue checkJ;
}
console.log(j, "– непарне число.");
}
console.log("i =", i);
console.log("j =", j);
}
Інструкція for...in
Інструкція for...in
ітерує заданою змінною по всіх перелічуваних властивостях об'єкта. Для кожної окремої властивості JavaScript виконує задані інструкції. Інструкція for...in
має наступний вигляд:
for (variable in object)
statement
Приклад
Наступна функція приймає аргументи з об'єкта та його імені. Потім вона ітерує по всіх властивостях цього об'єкта й повертає рядок, що перелічує імена властивостей та їх значення.
function dumpProps(obj, objName) {
let result = "";
for (const i in obj) {
result += `${objName}.${i} = ${obj[i]}<br>`;
}
result += "<hr>";
return result;
}
Для об'єкта car
з властивостями make
і model
result
буде:
car.make = Ford
car.model = Mustang
Масиви
Хоч може здаватись заманливим використати цю інструкцію як спосіб ітерації елементів Array
, for...in
поверне імена визначених користувачем властивостей на додачу до числових індексів.
Таким чином, краще використовувати для ітерування масивів традиційний цикл for
з числовим індексом, адже інструкція for...in
також ітерує по визначених користувачем властивостях, а не лише елементах масиву, що актуально, якщо об'єкт Array був змінений (тобто якщо були додані власні властивості чи методи).
Інструкція for...of
Інструкція for...of
утворює цикл, що ітерує ітеровані об'єкти (серед яких Array
, Map
, Set
, об'єкт arguments
і так далі), закликаючи особливий ітераційний гачок з інструкціями, котрі повинні бути виконані для значення кожної окремої властивості.
for (variable of iterable)
statement
Наступний приклад демонструє різницю між циклом for...of
і циклом for...in
. Коли for...in
ітерує імена властивостей, for...of
ітерує значення властивостей:
const arr = [3, 5, 7];
arr.foo = "привіт";
for (const i in arr) {
console.log(i);
}
// "0" "1" "2" "foo"
for (const i of arr) {
console.log(i);
}
// Виводить: 3 5 7
Інструкції for...of
і for...in
також можуть використовуватися вкупі з деструктуруванням. Наприклад, водночас можна обробляти в циклі як ключі, так і значення об'єкта, використовуючи Object.entries()
.
const obj = { foo: 1, bar: 2 };
for (const [key, val] of Object.entries(obj)) {
console.log(key, val);
}
// "foo" 1
// "bar" 2