Как пройтись по всем элементам массива в JavaScript
Что проверяют
Знаете ли вы больше одного способа и понимаете ли различия, которые действительно кусаются: можно ли прервать обход, что возвращается, как метод ведёт себя с дырами и с асинхронным колбэком.
Как отвечать
- Классический
forпо индексу иfor...ofподдерживаютbreak,continueиawaitв теле.for...ofработает с любым итерируемым: Set, Map, NodeList, строкой. Индекс достаётся черезarray.entries(). forEachпрервать нельзя:breakв нём синтаксическая ошибка,returnвыходит только из колбэка. Возвращаетundefined, поэтому в цепочку не встраивается.mapдля преобразования,filterдля отбора,reduceдля свёртки,find,someиeveryостанавливаются сами, как только результат определён. Вызыватьmapради побочного эффекта и выбрасывать результат неправильно, для этого естьforEach.- Дыры разреженного массива
forEach,mapиfilterпропускают,forиfor...ofотдаютundefined. При этомmapсохраняет дыры в результирующем массиве. for...inдля массивов не подходит: он обходит перечислимые строковые ключи, включая унаследованные и дописанные свойства, и отдаёт индексы строками.- Асинхронность:
awaitвнутриforEachне ждётся, колбэк просто вернёт промис. Последовательно, этоfor...ofсawait, параллельно,Promise.all(array.map(fn)).
for (const [i, item] of items.entries()) {
if (!item.ok) break;
await send(i, item);
}Где спотыкаются
Ставят await внутри forEach и удивляются, что код идёт дальше, не дождавшись запросов.
Пытаются выйти из forEach через return или break, а потом изобретают обход через some, хотя достаточно for...of.
Изменяют массив прямо во время перебора. forEach фиксирует длину на старте и добавленные элементы не посетит, а удаление сдвигает индексы и заставляет пропустить соседа.
Спорят о производительности на пустом месте. Разница видна только на очень больших массивах в горячем коде, выбирать нужно по нужной семантике и читаемости.