Цикл for - одна з найуживаніших інструкцій для багаторазового виконання певної логіки.
У JavaScript він складається з ключового слова for, заголовка в круглих дужках і блоку коду, що містить тіло циклу у фігурних дужках.
for (initialization; condition; step) {
// code that is executed repeatedly as long as the condition is
// true
}
Ініціалізація зазвичай створює змінну-лічильник, умова перевіряє, чи варто продовжити цикл, чи зупинити його, а крок збільшує лічильник наприкінці кожного повторення. Окремі частини заголовка розділяються крапками з комою.
const list = ['a', 'b', 'c'];
for (let i = 0; i < list.length; i++) {
// code that should be executed for each item in the array
}
Усі три частини заголовка необовʼязкові. На практиці це використовують рідко. Докладніше про це можна прочитати в документації MDN.
for
Цикли for можна вкладати один в один, наприклад, щоб перебрати вкладені (багатовимірні) масиви.
Подбаймо про те, щоб у кожного циклу була окрема змінна-лічильник.
const coords = [
[1, 2],
[4, 7],
[10, -3],
];
for (let i = 0; i < coords.length; i++) {
for (let j = 0; j < coords[i].length; j++) {
// do something with coords[i][j]
}
}
Усередині тіла циклу можна використати ключове слово break, щоб повністю зупинити виконання циклу.
Натомість ключове слово continue зупиняє лише виконання поточної ітерації та переходить до наступної.
Коли ми працюємо з вкладеними циклами, break і continue типово стосуються найглибшого циклу.
Змінити цю поведінку можна за допомогою міток.
Мітка - це імʼя ідентифікатора, після якого стоїть двокрапка.
Вона ставиться перед циклом (або над ним).
Таку мітку можна поєднати з break або continue, щоб визначити, до якого циклу має застосуватися інструкція.
outer: for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
// ...
if (j > 5) {
continue outer;
}
// ...
}
}
Варто бути уважними й правильно оголошувати змінну-лічильник, коли маємо справу з асинхронним кодом.
Розгляньмо приклад, де ми асинхронно додаємо значення лічильника за допомогою setTimeout після очікування 1 с.
Якщо оголосити лічильник через var або через let, але поза заголовком, код не дасть очікуваного результату.
let sum = 0;
for (var i = 1; i < 4; i++) {
setTimeout(function () { sum += i; }, 1000);
}
// eventually sum will be 12 instead of 6 (1+2+3)
let sum = 0;
let i;
for (i = 1; i < 4; i++) {
setTimeout(function () { sum += i; }, 1000);
}
// same here, eventually sum will be 12 instead of 6 (1+2+3)
У цих двох випадках i не належить до області видимості однієї конкретної ітерації циклу.
На момент обчислення суми i вже досягла свого кінцевого значення 4, і тому сума дорівнює 4 + 4 + 4 = 12.
Цієї проблеми можна уникнути, якщо оголосити лічильник через let усередині заголовка.
Це дає особливий ефект: кожна ітерація отримує власну змінну let i, область видимості якої обмежена саме одним виконанням тіла циклу.
Тож коли суму обчислюють пізніше, кожна функція зворотного виклику звертається до власної змінної i, яка все ще зберігає правильне значення.
let sum = 0;
for (let i = 1; i < 4; i++) {
setTimeout(function () { sum += i; }, 1000);
}
// eventually sum will be 6 (1+2+3) as expected