for...of
for…of
Level 4 — Iteration & Array Methods Iterates over the values of iterable objects like Arrays, Strings, Maps, and Sets.
1. Prerequisites
2. Term Category
Language Core (Introduced in ES6) (Universal: Works everywhere): for…of is a fundamental concept in this technology stack. Level 4 — Iteration & Array Methods
3. Explanation
(1) Design Motivation — "Why did we design this?"
While the traditional for loop (for (let i = 0; i < arr.length; i++)) is powerful, it is verbose and prone to "off-by-one" errors. Array methods like .forEach() solved this, but they have a massive limitation: you cannot use break to stop the loop early, or continue to skip an iteration.
In ES6, JavaScript introduced the for...of loop. It provides the clean, declarative syntax of .forEach() (no index management), but it is a real loop, meaning you can still use break and continue. Furthermore, it was designed to iterate over any "Iterable" data structure, not just Arrays—meaning you can easily loop through the individual characters of a String!
(2) Reality Metaphor
Imagine a Pez dispenser filled with candy. A traditional loop requires you to count the candies, track which number you are on, and manually pull each one out. for...of is like just pressing the dispenser's head: it hands you the next piece of candy (the value) automatically until the dispenser is completely empty.
(3) JavaScript Code Examples
Short Snippet
const colors = ["red", "blue", "green"];
// Reads as: "For every color OF colors..."
for (const color of colors) {
console.log(color);
}
// Outputs: "red", "blue", "green"
Fuller Example
const word = "HELLO";
// You can iterate over Strings!
for (const char of word) {
if (char === "L") {
continue; // Skip the 'L's
}
console.log(char);
}
// Outputs: "H", "E", "O"
const numbers = [10, 20, 30, 40, 50];
for (const num of numbers) {
if (num === 30) {
console.log("Found 30! Stopping early.");
break; // You can't do this in a .forEach()!
}
console.log(`Checking ${num}...`);
}
4. Common Mistakes & Pitfalls
Mistake 1: Trying to use for...of on standard Objects
The mistake: Attempting to loop through the key-value pairs of a plain JavaScript Object { name: "Alice", age: 28 } using for...of.
Why it's wrong: Plain Objects are not "Iterable" in JavaScript by default. They don't have a guaranteed order like Arrays do. If you try to use for...of on an object, the program will crash. (To loop over objects, use for...in or Object.keys()).
Incorrect:
const user = { name: "Alice", age: 28 };
// TypeError: user is not iterable
for (const item of user) {
console.log(item);
}
Fix:
const user = { name: "Alice", age: 28 };
// Get an array of the keys first!
for (const key of Object.keys(user)) {
console.log(`${key}: ${user[key]}`);
}
Mistake 2: Losing Context Binding (this) in For Of Callbacks
The mistake: Passing methods from For Of instances as standalone callbacks to timers or event listeners without explicitly binding this.
Why it's wrong: Extracting object methods disassociates them from their target parent instance, causing this to resolve to undefined (in strict mode) or window/globalThis at runtime.
Incorrect:
const obj = {
name: "for_of",
log() { console.log(this.name); }
};
setTimeout(obj.log, 100); // ❌ Output: undefined (loses object context)
Fix:
const obj = {
name: "for_of",
log() { console.log(this.name); }
};
setTimeout(() => obj.log(), 100); // Correct: Arrow function captures lexical context
Mistake 3: Unhandled Asynchronous Failures in For Of Operations
The mistake: Executing asynchronous operations within For Of without wrapping await calls in try...catch blocks or chaining .catch().
Why it's wrong: Unhandled promise rejections trigger UnhandledPromiseRejectionWarning in Node.js or unhandled rejection errors in modern browsers, leaving application state in corrupted or uncoordinated states.
Incorrect:
async function processData() {
const res = await fetch("/api/for_of"); // ❌ Unhandled network failure crashes execution flow
const data = await res.json();
return data;
}
Fix:
async function processData() {
try {
const res = await fetch("/api/for_of");
if (!res.ok) throw new Error(`HTTP Error: ${res.status}`);
return await res.json();
} catch (err) {
console.error(`Caught error in for_of: ${err.message}`);
return null;
}
}
5. Practice Exercises
Exercise 1: Iterable Collection & Map Iteration
Scenario: A cache manager iterates over key-value entries in a Map instance using a for…of loop.
Requirements:
- Write processMapEntries(mapInstance).
- Iterate entries using for (const [key, val] of mapInstance).
- Return processed object.
Answer
Implementation
function processMapEntries(mapInstance) {
const result = {};
if (!(mapInstance instanceof Map)) return result;
for (const [key, val] of mapInstance) {
result[key] = val;
}
return result;
}
// Verification tests
const myMap = new Map([["a", 1], ["b", 2]]);
const res = processMapEntries(myMap);
console.assert(res.a === 1 && res.b === 2, "Test 1 Failed");
Technical Explanation
- for…of Iteration Protocol: Iterates over iterable objects (Arrays, Maps, Sets, Strings, arguments) invoking their @@iterator method.
- Destructuring Support: Supports destructuring directly in loop variable declarations (for (const [k, v] of map)).
- Early Loop Control: Supports break, continue, and return statements to control execution flow.
6. Related Terms
- for…in — Used for iterating over the keys of an Object.
- forEach() — An array method that cannot be stopped with
break. - querySelectorAll & NodeList — Related concept: querySelectorAll & NodeList.
- for await…of / Async Iterators — Related concept: for await…of / Async Iterators.
- Iterators & Iterables (protocol) — Related concept: Iterators & Iterables (protocol).
7. Key Takeaways
for...ofiterates over the Values of an iterable data structure.- It works beautifully on Arrays and Strings.
- It does not work on plain Objects.
- Unlike
.forEach(), you can usebreakandcontinueinside afor...ofloop. - It is generally the preferred, modern way to write a standard loop.