array
javascript
loop

Loop (for each) over an array in JavaScript

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

JavaScript offers several ways to loop through arrays, and each one fits a different goal. forEach is convenient for side effects, for...of is flexible with control flow, and methods like map are best for creating transformed arrays. Choosing the right loop improves readability and avoids subtle async and mutation bugs.

forEach for Side-Effect Iteration

forEach runs a callback once for each element in array order.

javascript
1const items = ["a", "b", "c"];
2
3items.forEach((value, index) => {
4  console.log(index, value);
5});

Use it when you need to perform side effects such as logging, pushing into external arrays, or updating metrics.

Important behavior:

  • returns undefined
  • cannot break early with break or return from outer function
  • skips empty slots in sparse arrays

for...of for Flexible Control Flow

When you need break, continue, or early return semantics, for...of is usually better.

javascript
1const nums = [3, 5, 7, 9, 12, 15];
2
3for (const n of nums) {
4  if (n % 2 === 0) {
5    console.log("first even", n);
6    break;
7  }
8}

This style is especially useful in validations where you stop after first match or failure.

Classic for Loop for Index Control

Traditional for loop remains useful when index arithmetic matters.

javascript
1const values = [10, 20, 30, 40];
2
3for (let i = 0; i < values.length; i++) {
4  console.log(i, values[i]);
5}

Use this when you need neighboring elements, reverse traversal, or custom step sizes.

Use map, filter, and reduce for Data Transformation

If your goal is producing new data, array methods are often cleaner than side-effect loops.

javascript
1const prices = [12, 20, 7, 30];
2
3const discounted = prices.map(p => Math.round(p * 0.9));
4const expensive = discounted.filter(p => p >= 15);
5const total = expensive.reduce((sum, p) => sum + p, 0);
6
7console.log(discounted);
8console.log(expensive);
9console.log(total);

This style communicates transformation intent clearly.

Why for...in Is Usually Wrong for Arrays

for...in iterates enumerable keys, not guaranteed numeric sequence semantics for array iteration use cases.

javascript
1const arr = ["x", "y", "z"];
2for (const key in arr) {
3  console.log(key, arr[key]);
4}

It can work in simple cases but is better suited to object property iteration. Prefer for...of or forEach for arrays.

Async Iteration Gotcha with forEach

forEach does not await async callbacks.

javascript
1const ids = [1, 2, 3];
2
3ids.forEach(async id => {
4  await new Promise(r => setTimeout(r, 100));
5  console.log("done", id);
6});
7
8console.log("loop finished");

You will see loop-finished output before async tasks complete.

For sequential async processing, use for...of with await.

javascript
1for (const id of ids) {
2  await new Promise(r => setTimeout(r, 100));
3  console.log("done", id);
4}

For parallel execution, use Promise.all with map.

javascript
1await Promise.all(
2  ids.map(async id => {
3    await new Promise(r => setTimeout(r, 100));
4    return id;
5  })
6);

Mutating Arrays During Iteration

Mutating the iterated array can produce confusing behavior.

javascript
1const nums = [1, 2, 3, 4, 5];
2
3for (let i = 0; i < nums.length; i++) {
4  if (nums[i] % 2 === 0) {
5    nums.splice(i, 1);
6    i -= 1;
7  }
8}
9
10console.log(nums);

When removing items, reverse iteration or immutable filtering is often safer.

javascript
const cleaned = [1, 2, 3, 4, 5].filter(n => n % 2 !== 0);

Performance and Readability Balance

In most application code, readability matters more than tiny loop performance differences. Choose the construct that best expresses intent.

Practical guideline:

  • side effects only: forEach
  • early exit control: for...of or classic for
  • transform into new arrays: map, filter, reduce
  • async sequence: for...of with await

Keep style consistent within module for easier maintenance.

Common Pitfalls

A common pitfall is using forEach with async callbacks and assuming it waits automatically. Another is using for...in on arrays and getting unexpected key behavior. Teams also frequently mutate arrays while iterating without handling index shifts correctly. Finally, overusing one loop style for every task makes code harder to read than necessary.

Summary

  • Use loop style based on intent, not habit.
  • forEach is good for side effects but not for early exit or async waiting.
  • for...of is flexible and reliable for control flow.
  • map, filter, and reduce are best for transformations.
  • Avoid for...in for normal array iteration.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.