Looping is how you process every item in an array without writing repetitive manual code. This lesson compares the classic for loop, the modern for...of loop, and the functional .forEach() method ā and explains why for...in should never be used on arrays.
1JavaScript Loops Part 1
<h2>The Need for Iteration</h2><p>Data collections are useless if we can't process them efficiently. Imagine having an array of 500 users and needing to render a profile card for each one.</p><p>Writing out individual commands for all 500 users is impossible. <strong>Loops</strong> are the solution. They allow you to write a single block of code and instruct the JavaScript engine to execute it repeatedly for every item in your collection.</p>
const users = ['Ana', 'Bob', 'Carlos', 'Diana', 'Eve'];
// ā Manual ā not scalable
console.log(users[0]);
console.log(users[1]);
console.log(users[2]);
// ... 497 more?
// ā
Loop ā handles any length
for (const user of users) {
console.log(user);
}Automation
2JavaScript Loops Part 2
<h2>The Classic For Loop</h2><p>The traditional <code>for</code> loop gives you absolute, granular control over your iteration.</p><ul><li><strong>Initializer:</strong> <code>let i = 0</code> sets the starting point.</li><li><strong>Condition:</strong> <code>i < array.length</code> determines when the loop should stop.</li><li><strong>Increment:</strong> <code>i++</code> advances the counter after every cycle.</li></ul><p>By tweaking these three parameters, you can achieve complex iteration patterns.</p>
const colors = ['Red', 'Green', 'Blue', 'Yellow'];
// ā INIT ā” CONDITION ⢠INCREMENT
for (let i = 0; i < colors.length; i++) {
console.log(`Index ${i}: ${colors[i]}`);
}
// Output:
// Index 0: Red
// Index 1: Green
// Index 2: Blue
// Index 3: YellowFor Loop Anatomy
3JavaScript Loops Part 3
<h2>Advanced Control</h2><p>The classic <code>for</code> loop isn't just for moving forward one by one.</p><p>Because you control the math, you can loop backwards by starting at <code>length - 1</code> and decrementing (<code>i--</code>). You can skip elements by stepping by 2 (<code>i += 2</code>). And most importantly, you can exit the loop entirely at any moment using the <code>break</code> keyword if you find what you're looking for early.</p>
const nums = [10, 20, 30, 40, 50];
// Loop BACKWARDS
for (let i = nums.length - 1; i >= 0; i--) {
console.log(nums[i]); // 50, 40, 30, 20, 10
}
// SKIP every other item (step by 2)
for (let i = 0; i < nums.length; i += 2) {
console.log(nums[i]); // 10, 30, 50
}
// EXIT EARLY with break
for (let i = 0; i < nums.length; i++) {
if (nums[i] === 30) break; // stop here
console.log(nums[i]); // 10, 20
}Loop Superpowers
4JavaScript Loops Part 4
<h2>The Modern Standard: for...of</h2><p>While the classic loop is powerful, it's often overly verbose for simple arrays. The <code>for...of</code> loop is the modern standard.</p><p>It abstracts away the index management entirely, extracting the <strong>value</strong> of each element directly into a variable. It prevents "off-by-one" errors and makes your code much easier to read.</p>
const tasks = ['Design UI', 'Write API', 'Deploy'];
// ā
for...of ā clean, direct value access
for (const task of tasks) {
console.log(task);
}
// 'Design UI'
// 'Write API'
// 'Deploy'
// Works with any iterable: strings, Maps, Sets
for (const char of 'Hello') {
console.log(char); // H, e, l, l, o
}for...of Magic
5JavaScript Loops Part 5
<h2>The for...in Bug</h2><p>A very common and dangerous mistake is using <code>for...in</code> instead of <code>for...of</code> on an array.</p><p><code>for...in</code> iterates over the <strong>keys</strong> of an object. For arrays, these keys are the indices, but they are returned as <em>Strings</em> (e.g., "0", "1"). If you try to do math with them, you'll end up with string concatenation bugs (e.g., "0" + 1 = "01"). Never use <code>for...in</code> on arrays!</p>
const scores = [85, 92, 78];
// ā
for...of ā VALUES
for (const score of scores) {
console.log(score); // 85, 92, 78 (numbers)
console.log(typeof score); // 'number'
}
// ā for...in ā KEYS (as strings!)
for (const key in scores) {
console.log(key); // '0', '1', '2' (strings!)
console.log(typeof key); // 'string'
console.log(key + 1); // '01', '11', '21' ā BUG!
}The for...in Bug
6JavaScript Loops Part 6
<h2>Functional Iteration: .forEach()</h2><p>The <code>.forEach()</code> method embraces a functional programming style.</p><p>Instead of setting up a loop structure, you pass a <strong>callback function</strong> to <code>.forEach()</code>. The engine will execute this function once for every element in the array, automatically passing the value, the index, and the original array as arguments to your callback.</p>
const products = ['Laptop', 'Mouse', 'Keyboard'];
// Basic forEach ā value only
products.forEach(product => {
console.log(product);
});
// Full signature: (value, index, array)
products.forEach((product, index, arr) => {
console.log(`${index + 1}/${arr.length}: ${product}`);
});
// '1/3: Laptop'
// '2/3: Mouse'
// '3/3: Keyboard'Functional Callback
7JavaScript Loops Part 7
<h2>Limitations of .forEach()</h2><p>While <code>.forEach()</code> is elegant, it has a strict limitation: <strong>you cannot break out of it early.</strong></p><p>Using the <code>return</code> keyword inside the callback only exits that specific execution of the callback. The loop will relentlessly continue to process the rest of the array. If you need the ability to short-circuit or break early, use a <code>for...of</code> loop instead.</p>
const nums = [1, 2, 3, 4, 5];
// ā Cannot break out of forEach
nums.forEach(n => {
if (n === 3) return; // skips 3, but 4 and 5 still run
console.log(n); // 1, 2, 4, 5
});
// ā
Use for...of when you need break
for (const n of nums) {
if (n === 3) break; // actually stops the loop
console.log(n); // 1, 2
}No Break in forEach!
8JavaScript Loops Part 8
<h2>Loops Mastered</h2><p>Congratulations! You now have a complete iteration toolkit.</p><p>You know when to use the classic loop for index control, the <code>for...of</code> loop for clean value extraction, and <code>.forEach()</code> for functional callbacks. These patterns will be used in almost every JavaScript application you build.</p>
Loops Mastered
9Step-by-Step Breakdown
Imagine you have an array of 500 users. Writing console.log() 500 times is absurd. Loops are the primary mechanism for iteration ā they let you run the EXACT SAME code for EVERY item in a collection automatically.
The classic for loop has three parts: INITIALIZER sets your starting index, CONDITION decides when to stop, and INCREMENT advances the counter each time. You get total control over every iteration.
The classic for loop's real power is its precision. You can loop backwards, skip indices by stepping by 2, or exit completely early using break. No other loop gives you this level of index control.
Checkpoint: What part of the classic for loop defines WHEN the iteration should stop?
- ālet i = 0 (initializer)
- āi < 5 (condition)
- āi++ (increment)
for...of is the modern standard for array iteration. It extracts the VALUES directly ā no index variable, no .length, no off-by-one risk. You should use it for 90% of your daily iteration.
CRITICAL: for...of gives you VALUES. for...in gives you KEYS (as strings). Using for...in on arrays causes subtle bugs because the indices come back as strings, not numbers. This leads to string concatenation bugs instead of math addition.
.forEach() is an array method that embraces functional programming. It takes a CALLBACK function and runs it once per element. The callback automatically receives: the VALUE, the INDEX, and the full ARRAY.
There's an important limitation to .forEach(): you CANNOT break out of it early. Using the 'return' keyword inside the callback only skips that specific callback run ā it does NOT stop the overall loop. If you need early exit capabilities, use for...of with a break statement.
Checkpoint: Does .forEach() automatically return a new modified array?
- āYes ā it transforms the data
- āNo ā it returns undefined
Checkpoint: Which loop is preferred for iterating directly over the VALUES of an array in modern JavaScript?
- āfor...in (iterates keys)
- āfor...of (iterates values)
Iteration toolkit complete! Use the classic for loop for total control, for...of for clean value extraction, and .forEach() for functional callbacks. Never use for...in on arrays. Next up: DOM Manipulation.
Level Up š
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Loop-Generated Lists Need Semantic Wrappers and Stable Keys
When a loop (for...of, .map(), .forEach()) builds a list of UI elements, the output should be placed inside a semantic `<ul>`/`<ol>` with `<li>` children ā a flat sequence of `<div>`s built by a loop gives screen readers no indication it's a list, its length, or each item's position.
SEO Implications
- 1
Loops That Run Only After a Client-Side Fetch Can Delay or Hide Content from Crawlers
If visible page content is generated by looping over data that only arrives after a client-side network request, crawlers that don't wait for that JavaScript to finish may index a blank or partial page. Rendering the looped content server-side avoids this gap entirely.
Best Practices
Default to for...of, Reach for a Classic for Loop Only When You Need the Index
for...of is shorter, avoids off-by-one errors, and works on any iterable. Use the classic for loop only when you specifically need manual index control ā backwards iteration, skipping elements, or stopping with break inside a callback-based method that doesn't support it.
Never Use for...in to Iterate Over Arrays
for...in enumerates keys, which for an array are numeric indices returned as strings ā mixing them into arithmetic produces string concatenation bugs like '0' + 1 === '01'. Reserve for...in for plain objects, and use for...of or array methods for arrays.
Frequent Bugs
Using `array.forEach()` and expecting `break` or `return` to stop the whole loop early.
`return` inside a forEach callback only exits that single callback invocation ā the loop continues over every remaining element regardless. If you need to stop iterating early, use a `for...of` loop or the classic `for` loop, both of which support a real `break`.
Looping over an array with `for...in` and getting unexpected results when doing arithmetic with the loop variable.
`for...in` returns each index as a string, not a number, so `key + 1` concatenates instead of adding (`'2' + 1` becomes `'21'`, not `3`). Use `for...of` (for values) or a classic `for` loop with a numeric counter instead.
Real-World Examples
Rendering a Task List While Stopping at the First Incomplete Item
A project dashboard needed to find and highlight the first incomplete task in an ordered array of tasks, then stop looking ā a job unsuited to .forEach() since it can't be short-circuited.
const tasks = [
{ name: 'Design UI', done: true },
{ name: 'Write API', done: false },
{ name: 'Deploy', done: false },
];
let firstIncomplete = null;
for (const task of tasks) {
if (!task.done) {
firstIncomplete = task;
break;
}
}