Loops & Iteration
Reviewed & published by Brayan K
Computers are brilliant at doing the same thing thousands of times without complaint. Loops are how you tell them to — rendering a list of products, summing a cart, retrying a request, or scanning a file line by line.
Part of the free JavaScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
You'll learn the four loop forms, when each one fits, and how to steer them with break and continue.
What You'll Learn in This Lesson
- The classic for loop and its three parts
- while and do…while for condition-based repeats
- for…of for values, for…in for keys
- Steering loops with break and continue
- Looping objects with Object.entries
- Avoiding infinite loops and off-by-one errors
🏃 Real-World Analogy: A loop is like running laps at a track:
- • The start sets your lap counter to 0
- • The condition ("under 10 laps?") is checked before every lap
- • The body is the lap itself
- • break is quitting early; continue is skipping the rest of one lap
🧠 The Classic for Loop
The for loop bundles three parts in its header: an initializer, a condition checked before each pass, and an update run after each pass. Use it when you know how many times to repeat.
⏳ while & do…while
A while loop repeats as long as its condition is true and is perfect when you don't know the count ahead of time. A do…while runs the body once before checking, guaranteeing at least one pass.
🎯 for…of vs for…in — Don't Mix Them Up
This is the single most common loop confusion. for…of walks the values of an iterable; for…in walks the keys of an object. Using the wrong one on an array gives surprising results.
Spot the trap: for…in gave indices as the strings "0", "1", "2" — that's why it's wrong for arithmetic on array positions.
🛑 break & continue
break abandons the whole loop; continue skips to the next iteration. They turn a blunt loop into a precise search-or-filter tool.
📋 Which Loop Should I Use?
| Loop | Best for | Gives you |
|---|---|---|
| for | Known count, need index | A counter you control |
| while | Repeat until a condition flips | Condition-driven looping |
| do…while | Must run at least once | Guaranteed first pass |
| for…of | Array/string/Map values | Each value directly |
| for…in | Object keys | Each property name |
// 🎯 YOUR TURN — replace each ___ using the hint beside it.
const basket = [
{ item: "apples", qty: 3, price: 0.6 },
{ item: "bread", qty: 0, price: 1.2 },
{ item: "cheese", qty: 1, price: 4.5 },
{ item: "olives", qty: 2, price: 3.0 },
];
let total = 0;
// 1) Stop BEFORE the length, never at it — the last index is length - 1.
for (let i = 0; i ___ basket.length; i++) { // 👉 replace ___ with <
const line = basket[i];
// 2) Nothing ordered: skip to the next turn of the loop.
if (line.qty === 0) ___; // 👉 replace ___ with continue
total += line.qty * line.price;
}
console.log("Total:", total.toFixed(2));
// 3) for...of gives you the VALUE. for...in would give you the index.
for (const line ___ basket) { // 👉 replace ___ with of
if (line.item === "cheese") {
console.log("Found cheese, stopping the walk");
break; // leaves the loop entirely
}
console.log("Checked", line.item);
}
// 4) One output per input: that is map.
const names = basket.___((l) => l.item); // 👉 replace ___ with map
console.log("Names:", names.join(", "));
// 5) Keep only the ones that pass the test: that is filter.
const inStock = basket.___((l) => l.qty > 0); // 👉 replace ___ with filter
console.log("In stock:", inStock.length);
let countdown = 3;
while (countdown > 0) {
console.log("Closing in", countdown);
countdown--; // forget this and it never ends
}
// ✅ Expected output:
// Total: 12.30
// Checked apples
// Checked bread
// Found cheese, stopping the walk
// Names: apples, bread, cheese, olives
// In stock: 3
// Closing in 3
// Closing in 2
// Closing in 1🧩 Reorder Challenge
These lines should sum only the even numbers in an array and print the total. They are scrambled — reorder them so the log is Sum: 6 for [1, 2, 3, 4].
B → D → A → C → E → F
Why: the accumulator (B) must be declared before the loop so it survives across iterations. Inside, the continue guard (A) must come before the addition (C), otherwise odd numbers would be added before being skipped. The closing brace (E) ends the loop, and the log (F) runs once at the end. Only 2 and 4 are added: 2 + 4 = 6.
🧠 Quick Recall
0 then 2. When i is 1, continue skips the console.log for that pass only, so 1 is never printed but the loop carries on.
2. What does this log?
01 then 11. for…in gives string indices "0" and "1", so i + 1 is string concatenation: "0" + 1 = "01". This is exactly why for…of is preferred for arrays.
3. How many times does the body run?
Once — it logs 5. do…while runs the body before checking the condition. After x becomes 6, x < 5 is false, so it stops. A plain while would never have run at all.
⚠️ Common Mistakes to Avoid
- 1️⃣ Infinite loops. Forgetting to update the counter (or the condition can never become false) freezes the program. Always ensure progress toward the exit.
- 2️⃣ Off-by-one errors. i <= arr.length reads one past the end; use i < arr.length.
- 3️⃣ for…in on arrays. It yields string keys and can include inherited properties — use for…of.
- 4️⃣ Declaring with var in loops. let gives a fresh binding per iteration, fixing closure bugs in async callbacks.
Lesson Complete — Loops & Iteration!
- ✅ for for known counts, while/do…while for conditions
- ✅ for…of gives values, for…in gives object keys
- ✅ break exits the loop; continue skips one iteration
- ✅ Guard against infinite loops and off-by-one errors
Practice quiz
How many times does the body of this loop run: for (let i = 1; i <= 5; i++)?
- 4
- 6
- 5
- Infinite
Answer: 5. It runs for i = 1,2,3,4,5 — that's 5 iterations because the condition is i <= 5.
Which loop is guaranteed to run its body at least once, even if the condition is false from the start?
- do…while
- for
- while
- for…of
Answer: do…while. do…while runs the body first and checks the condition afterward, so it always runs at least once.
What does for…of give you when looping over an array?
- The keys/indices
- String indices like '0','1'
- Nothing — it errors on arrays
- The values (each element)
Answer: The values (each element). for…of walks the VALUES of an iterable, giving you each element directly.
What does for…in give you when looping over an object?
- The values
- The keys (property names)
- Index numbers
- Entries as [key, value] pairs
Answer: The keys (property names). for…in walks the KEYS (property names) of an object.
What does this log? const arr = ['a','b']; for (const i in arr) { console.log(i + 1); }
- 01 then 11
- 1 then 2
- a1 then b1
- 0 then 1
Answer: 01 then 11. for…in yields string indices '0' and '1', so i + 1 is string concatenation: '0'+1='01', '1'+1='11'.
In a for…in loop over an array, what is the type of each index value?
- number
- boolean
- string
- undefined
Answer: string. for…in gives indices as STRINGS like '0','1','2', which is why it's wrong for arithmetic on array positions.
What is the difference between break and continue?
- break skips one iteration; continue exits the loop
- break exits the whole loop; continue skips to the next iteration
- Both exit the loop entirely
- Both only skip the current iteration
Answer: break exits the whole loop; continue skips to the next iteration. break abandons the whole loop immediately; continue skips only the rest of the current iteration.
What does this log? let x = 5; do { console.log(x); x++; } while (x < 5);
- Nothing
- 5 then 6
- Infinite numbers
- 5
Answer: 5. do…while runs the body once first, logging 5; then x becomes 6 and x < 5 is false, so it stops.
Sum of evens — what does this log? const nums = [4,7,11,3,20]; let sum = 0; for (const n of nums) { if (n % 2 !== 0) continue; sum += n; } console.log(sum);
- 45
- 24
- 20
- 31
Answer: 24. continue skips odd numbers (7,11,3); only 4 and 20 are added: 4 + 20 = 24.
Which is the recommended way to avoid an off-by-one error when looping an array by index?
- for (let i = 0; i <= arr.length; i++)
- for (let i = 1; i <= arr.length; i++)
- for (let i = 0; i < arr.length; i++)
- for (let i = 0; i =< arr.length; i++)
Answer: for (let i = 0; i < arr.length; i++). Use i < arr.length; using i <= arr.length reads one past the end of the array.
Continue this course
- Previous: Numbers & Math
- Next: Conditionals & Operators — if/else, switch, ternary, &&/||, plus ?? and ?. (optional chaining)
- Quick reference: JavaScript cheat sheet
Frequently asked questions
When should I use for…of versus for…in?
Use for…of to loop the VALUES of an iterable like an array or string — it gives you each element directly. Use for…in to loop the KEYS of an object. A frequent bug is using for…in on an array, which gives you string indices ('0','1','2') and can include inherited properties. For arrays, prefer for…of or forEach.
What's the difference between break and continue?
break exits the entire loop immediately — no more iterations run. continue skips only the rest of the current iteration and jumps to the next one. Use break when you've found what you need; use continue to skip items that don't qualify.
Should I use a for loop or array methods like map and forEach?
Array methods (map, filter, forEach, reduce) are more declarative and usually clearer for transforming data. Classic for loops shine when you need the index, want to skip or jump with break/continue, or care about raw performance in a hot path. Both are correct — pick the one that reads best for the task.
Why does my for loop with var print the same number every time in a setTimeout?
var is function-scoped, so a single variable is shared across all iterations; by the time the timers fire, the loop has finished and the variable holds its final value. Using let instead creates a fresh binding per iteration, so each callback captures the correct value. This is the classic reason let replaced var in loops.
How do I loop a fixed number of times versus 'until a condition'?
Use a for loop when you know the count up front: for (let i = 0; i < 10; i++). Use a while loop when you repeat until some condition changes and don't know the count in advance, like reading input until it's empty. Use do…while when the body must run at least once before the check.