Read 5 min
Использование циклов в JS
Базовые циклы for
, while
, do...while
Есть 3 базовых конструкции которые существуют с самых ранних стандартов ECMAScript и позволяют осуществлять итерацию по структурам данных:
for
- наиболее часто распространенная конструкцияdo...while
- используется крайне редко, обычно предпочтение отдается в пользуfor
while
- используется редко, обычно предпочтение отдается в пользуfor
C их помощью можно итерировать различные структуры данных, например массивы:
Цикл for
const arr = ['a', 'b', 'c'];
for (let index = 0; index < arr.length; index++) {
console.log(arr[index]);
}
Цикл while
const arr = ['a', 'b', 'c'];
let index = 0;
while (index < arr.length) {
console.log(arr[index]);
index++;
}
Цикл do...while
const arr = ['a', 'b', 'c'];
let index = 0;
do {
console.log(arr[index]);
} while (++index < arr.length);
Однако, данные циклы неудобны тем, что приходится вручную объявлять переменные index
увеличивать их index++
, следить за условием index < arr.length
Более того, если допустить ошибку есть вероятность влипнуть в бесконечный цикл при использовании while
и do...while
, а это отберет у вас драгоценное время разработки, которое вы потратите на то чтобы убить вкладку браузера, если конечно он не сделает это за вас, через какое-то время, но это не точно :)
Итерируемые структуры данных
Итерация с помощью метода forEach
Для итерации по массивам и некоторым другим коллекциям данных можно использовать встроенный метод forEach
const arr = ['a', 'b', 'c'];
arr.forEach((item, index) => {
console.log(item);
});
Но у данного метода есть недостаток - он не поддерживает управляющие конструкции break
и continue
, и return false
также не оборвет итерацию, поэтому следует использовать данный метод только в том случае когда нет необходимости оборвать процесс итерации
Чтобы исправить положение связанное с невозможностью использования break
и continue
на помощь приходит цикл for...of
Итерация с помощью метода for...of
Данный цикл появился с приходом стандарта ECMAScript 2015 (ES6) и позволяет итерировать различные структуры данных: массивы, Map/WeackMap, Set/WeackSet, NodeList
const arr = ['a', 'b', 'c'];
for (const item of arr) {
console.log(item);
}
Более того, он поддерживает управляющие конструкции break
и continue
,
а итерация происходит по собственным перечисляемым свойствам итерируемых объектов.
И все бы хорошо, но как заметно из сигнатуры данного цикла, в нем нет возможности использовать индекс итерируемых данныx.
Для решения данной проблемы можно использовать встроенный метод массива entries
:
for (const [index, value] of ['a', 'b', 'c'].entries()) {
console.log(index, value);
}
Итерация по свойствам объектов
Итерация с помощью метода for...in
Для итерации по объектам можно применять цикл for...in
, но у него есть ряд недостатков:
-
перебор происходит по алгоритму: "сначала целочисленные свойства, затем свойства в порядке добавления" - подробнее тут
-
в отличии от
for...of
он перебирает все свойства объектов как собственные так и унаследованные
const parent = {
color: 'red'
};
const child = {
fruite: 'apple'
};
child.__proto__ = parent;
for (const prop in child) {
console.log(child[prop]);
}
// 'apple'
// 'red'
Чтобы исправить, можно добавить проверку с использование метода hasOwnProperty
который проверит собственное ли свойства:
const parent = {
color: 'red'
};
const child = {
fruite: 'apple'
};
child.__proto__ = parent;
for (const prop in child) {
if (child.hasOwnProperty(prop)) {
console.log(child[prop]);
}
}
// 'apple'
Но лучше отдавать предпочтение для итерации по объектам c помощью for...of
в связке с одним из методов:
Object.keys
Object.values
Object.entries
Они возвращают массив только собственных значений объекта:
for (const [key, value] of Object.entries(obj)) { /* logic */}
for (const key of Object.keys(obj)) { /* logic */ }
for (const value of Object.values(obj)) { /* logic */ }
Вывод:
На практике целесообразно использовать следующие циклы:
forEach
- если нет необходимости "оборвать" итерациюfor...of
во всех других случаях, в том числе и для итерации по объектам