JavaScriptFor Loop

for loop

The classic C-style for loop is the oldest and most general loop in JavaScript. It gives you full control over three things: where the loop starts, when it stops, and how the counter changes on each pass. Most of the time you'll prefer forEach, for...of or array methods — but when you need that control, nothing else fits.

The three-part header

A for loop has three semicolon-separated parts inside its parentheses:

JS
for (let i = 0; i < 5; i++) {
  console.log(i);
}
0
1
2
3
4
  • Init (let i = 0) runs once before the loop begins.

  • Condition (i < 5) is checked before each iteration. If it is falsy, the loop ends.

  • Update (i++) runs after each iteration, before the condition is checked again.

Each part is optional. for (;;) { ... } is a perfectly legal infinite loop — handy when you intend to break out from inside.

Iterating an array

The textbook use case: walk an array by index.

JS
const words = ["alpha", "beta", "gamma"];

for (let i = 0; i < words.length; i++) {
  console.log(i, words[i]);
}
0 alpha
1 beta
2 gamma

Notice the cache opportunity: if words.length is expensive (it isn't on a plain array, but it can be on a DOM NodeList), hoist it out: for (let i = 0, n = words.length; i < n; i++).

Counting backwards and by steps

The update expression doesn't have to be i++. Anything that converges towards the condition works.

Backwards

JS
for (let i = 10; i > 0; i--) {
  console.log(i);
}

By twos

JS
for (let i = 0; i < 20; i += 2) {
  console.log(i);
}

Two counters at once

JS
for (let left = 0, right = arr.length - 1; left < right; left++, right--) {
  // converge from both ends — useful for in-place reversals, palindrome checks
}
Scoping pitfalls with var

The single biggest reason let exists is the loop. var is function-scoped, so every iteration shares the same counter — which destroys closures created inside the loop.

var — all three timeouts share one i

JS
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log("var:", i), 100);
}
// var: 3
// var: 3
// var: 3

let — each iteration gets a fresh i

JS
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log("let:", i), 100);
}
// let: 0
// let: 1
// let: 2
Use let in loop counters
If you only remember one thing from this page, it is this: write `for (let i = ...)`, not `for (var i = ...)`. It eliminates the classic loop-and-closure bug for free.
break and continue

break ends the loop immediately. continue skips the rest of the current iteration and goes to the update step.

JS
for (let i = 0; i < 10; i++) {
  if (i === 5) break;          // stop the whole loop at 5
  if (i % 2 === 0) continue;   // skip even numbers
  console.log(i);
}
1
3
When to choose for over forEach

Array methods like forEach are usually nicer to read, but for still wins in a few situations:

  • You need to break out earlyforEach cannot break; for, for...of and some/every can.

  • You need the index and you also need to skip ahead (i += 2, i -= 1) — forEach always increments by one.

  • You are walking multiple arrays in lockstep with the same index.

  • You are in a tight performance loop over millions of elements — for is reliably the fastest, though the difference rarely matters.

Early exit — for wins

JS
function indexOf(arr, target) {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] === target) return i;
  }
  return -1;
}
for...of vs classic for
When you don't need the index, `for (const item of arr)` reads better than `for (let i = 0; ...) { const item = arr[i]; }`. Reach for the classic `for` only when the index is genuinely part of the logic.
Nested loops

Looping inside a loop is fine — but the cost is multiplicative. A 1000×1000 nested loop is a million iterations, which is the boundary where you should ask if a different data structure (Set, Map) would let you flatten it.

JS
const grid = [
  [1, 2, 3],
  [4, 5, 6],
];

for (let r = 0; r < grid.length; r++) {
  for (let c = 0; c < grid[r].length; c++) {
    console.log(`[${r}][${c}] = ${grid[r][c]}`);
  }
}
Infinite loops on purpose

for (;;) { ... break; } is the canonical way to say "loop forever until I say stop". It is functionally identical to while (true); pick whichever your team finds clearer.

JS
for (;;) {
  const chunk = readNextChunk();
  if (chunk === null) break;
  process(chunk);
}
One sentence to remember
Use the classic `for` loop when you genuinely need the index, an unusual step size, or early exit — and reach for `for...of` or array methods for everything else.