---
title: "07 — Loops and Iteration — Five Constructs, One Mental Model"
uid: loops-and-iterations
tags: ["for", "for-in", "roadmap:javascript", "iteration", "while", "for-of", "loops", "javascript"]
excerpt: "Each loop construct answers a different question — known count, unknown count, iterable values, object keys — and the wrong one is usually for...in on an array."
date: 2026-08-13T03:28:06+0000
source: https://www.aveshina.my.id/en/blog/loops-and-iterations
---

"A few flavors of for" was my loop mental model, and it made each flavor feel interchangeable. The idea that everything else hangs off: **each loop construct answers a different question, and picking the wrong question is the bug — most often, reaching for for...in on an array when I meant for...of.** [1]

The framing that finally landed is matching the construct to the question I'm actually asking:

```figure
<svg viewBox="0 0 740 260" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-2xl" role="img" aria-label="Four loop constructs mapped to four questions. for: how many times (count known). while / do-while: until some condition (count unknown). for...of: each value of an iterable. for...in: each key of an object. for...in on an array is crossed out as a mistake.">
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">
    <!-- for -->
    <rect x="20" y="30" width="165" height="95" rx="10" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
    <text x="102" y="55" font-size="13" font-weight="700" font-family="ui-monospace,monospace" fill="#1e1b4b" text-anchor="middle">for</text>
    <text x="102" y="80" font-size="10" fill="#475569" text-anchor="middle">how many times?</text>
    <text x="102" y="100" font-size="9.5" font-style="italic" fill="#64748b" text-anchor="middle">count known up front</text>

    <!-- while/do-while -->
    <rect x="200" y="30" width="165" height="95" rx="10" fill="#dcfce7" stroke="#16a34a" stroke-width="1.5"/>
    <text x="282" y="55" font-size="13" font-weight="700" font-family="ui-monospace,monospace" fill="#052e16" text-anchor="middle">while / do…while</text>
    <text x="282" y="80" font-size="10" fill="#475569" text-anchor="middle">until a condition?</text>
    <text x="282" y="100" font-size="9.5" font-style="italic" fill="#64748b" text-anchor="middle">count unknown</text>

    <!-- for-of -->
    <rect x="380" y="30" width="165" height="95" rx="10" fill="#fef9c3" stroke="#ca8a04" stroke-width="1.5"/>
    <text x="462" y="55" font-size="13" font-weight="700" font-family="ui-monospace,monospace" fill="#422006" text-anchor="middle">for…of</text>
    <text x="462" y="80" font-size="10" fill="#475569" text-anchor="middle">each value?</text>
    <text x="462" y="100" font-size="9.5" font-style="italic" fill="#64748b" text-anchor="middle">arrays, strings, Map, Set</text>

    <!-- for-in -->
    <rect x="560" y="30" width="165" height="95" rx="10" fill="#fce7f3" stroke="#db2777" stroke-width="1.5"/>
    <text x="642" y="55" font-size="13" font-weight="700" font-family="ui-monospace,monospace" fill="#500724" text-anchor="middle">for…in</text>
    <text x="642" y="80" font-size="10" fill="#475569" text-anchor="middle">each key?</text>
    <text x="642" y="100" font-size="9.5" font-style="italic" fill="#64748b" text-anchor="middle">object properties</text>

    <!-- warning -->
    <rect x="200" y="160" width="525" height="70" rx="10" fill="#fee2e2" stroke="#dc2626" stroke-width="1.5"/>
    <text x="462" y="186" font-size="11" font-weight="700" fill="#7f1d1d" text-anchor="middle">✕  for…in on an array</text>
    <text x="462" y="206" font-size="10" fill="#7f1d1d" text-anchor="middle">iterates enumerable property names (including non-numeric ones),</text>
    <text x="462" y="220" font-size="10" fill="#7f1d1d" text-anchor="middle">order isn't guaranteed — almost always a mistake. Use for…of.</text>
  </g>
</svg>
```

## Count known: the classic for

The plain for loop is for when I know the iteration count up front — a counter, a condition, and an increment, all in the header [2]:

```
for (let i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}
```

It's the most flexible construct (I control the index, the step, the direction), but in modern code I reach for it only when for...of or an array method can't express what I need — say, iterating two arrays in parallel by index.

## Count unknown: while and do...while

When the number of iterations isn't known in advance — reading from a stream until empty, retrying until success — while is the right shape [3]. The condition is checked *before* each iteration, so the body may run zero times:

```
while (queue.length > 0) {
  process(queue.shift());
}
```

do...while is the variant that checks the condition *after* the body, guaranteeing at least one run [4]. It's the right choice when the first iteration must always happen — prompt-then-validate loops, menu renderers.

## Values of an iterable: for...of

for...of is the loop I write most. It iterates over the *values* of any **iterable** — arrays, strings, Maps, Sets, TypedArrays, generators, DOM NodeLists [5]:

```
for (const item of items) { /* item is a value */ }
for (const [key, value] of map) { /* destructure entries */ }
```

It's clean, it's safe (no index to go out of bounds), and it works uniformly across every collection that matters. The rule of thumb: if I'm walking the *values* of a collection, this is the default.

## Keys of an object: for...in

for...in is the one with the trap. It iterates over the **enumerable property names** (keys) of an object, including inherited ones, and it does *not* guarantee order [6]. That makes it right for one job — walking an object's keys — and wrong for almost everything else:

```
const obj = { a: 1, b: 2 };
for (const key in obj) {
  console.log(key, obj[key]); // "a" 1, "b" 2
}
```

The classic mistake is using for...in on an array. It technically works (array indices are enumerable string properties), but it also picks up any extra properties added to the array, the order isn't guaranteed, and it's slower. For arrays, it's always for...of or an array method.

The modern alternative to for...in on a plain object is Object.keys(obj), Object.entries(obj), or Object.values(obj) — they return an array I can for...of over, with predictable order and no inherited-property surprises.

## break and continue

Two flow-control statements work inside any loop [7]:

- **break** — exit the loop entirely, skipping remaining iterations.
- **continue** — skip the rest of this iteration, jump to the next.

Both can take a *label* to control an outer loop from inside a nested one (outer: for (...) { for (...) { break outer; } }), though labeled breaks are rare in practice — refactoring usually reads better.

## Array methods as the hidden loop

The thing I have to remind myself: half the loops I used to write don't need a loop statement at all. map, filter, reduce, find, some, every, forEach are all iteration — they just express *what* to do with each element rather than *how* to walk them. When the body is a pure transformation, an array method reads cleaner than a for and avoids index bugs. I reserve explicit loops for stateful iteration (early break, side-effect accumulation) where a method doesn't fit.

## How I use this

The decision is now reflexive. Walking values of an array, string, Map, or Set → **for...of**. Walking keys of a plain object → Object.keys() + for...of, or for...in if I have a reason. Count known → **for**. Count unknown, body may run zero times → **while**. Count unknown, body must run at least once → **do...while**. Pure transformation → an **array method**, no loop keyword at all. And for...in on an array is a smell I flag in review every time.

## References

[1] Mozilla, "Loops and iteration," MDN Web Docs, 2024. [Online]. Available: [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration)

[2] Mozilla, "for statement," MDN Web Docs, 2024. [Online]. Available: [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for)

[3] Mozilla, "while statement," MDN Web Docs, 2024. [Online]. Available: [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/while](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/while)

[4] Mozilla, "do...while statement," MDN Web Docs, 2024. [Online]. Available: [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/do...while](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/do...while)

[5] Mozilla, "for...of statement," MDN Web Docs, 2024. [Online]. Available: [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of)

[6] Mozilla, "for...in statement," MDN Web Docs, 2024. [Online]. Available: [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in)

[7] Mozilla, "break and continue statements," MDN Web Docs, 2024. [Online]. Available: [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/break](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/break)

```quiz
Q: Which loop iterates over the VALUES of an array, string, Map, or Set?
- for...in
- for...of
correct: 1
explain: for...of walks the values of any iterable (Array, String, Map, Set, TypedArray, NodeList, generators). for...in walks the enumerable keys of an object — a different job.

Q: Why is for...in a mistake on an array?
- It iterates enumerable property names (including non-numeric ones added to the array), order isn't guaranteed, and it's slower
- It throws a TypeError
correct: 0
explain: Array indices are enumerable string properties, so for...in technically works, but it also picks up any extra properties, doesn't guarantee order, and is slower. Use for...of or an array method.

Q: When do you choose do...while over while?
- When the body must run at least once before the condition is checked
- When the count is known up front
correct: 0
explain: do...while checks the condition AFTER the body, guaranteeing one execution. while checks before, so the body may run zero times.

Q: What does continue do inside a loop?
- Exits the loop entirely
- Skips the rest of the current iteration and moves to the next
correct: 1
explain: continue jumps to the next iteration, skipping the remaining statements in the current one. break exits the whole loop.

Q: The modern, order-guaranteed alternative to for...in over a plain object is…
- Object.keys() / Object.entries() / Object.values() combined with for...of
- delete the inherited properties and retry
correct: 0
explain: Object.keys/entries/values return an array of the object's own enumerable string-keyed properties in a defined order, which you can then for...of over. Cleaner and safer than for...in.
```
