03-javascriptTermsLevel_04for...of

for…of

Level 4 — Iteration & Array Methods Iterates over the values of iterable objects like Arrays, Strings, Maps, and Sets.


1. Prerequisites

  • Array — An ordered list of values.
  • for Loop — The traditional counting loop.

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:

  1. Write processMapEntries(mapInstance).
  2. Iterate entries using for (const [key, val] of mapInstance).
  3. 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

  1. for…of Iteration Protocol: Iterates over iterable objects (Arrays, Maps, Sets, Strings, arguments) invoking their @@iterator method.
  2. Destructuring Support: Supports destructuring directly in loop variable declarations (for (const [k, v] of map)).
  3. Early Loop Control: Supports break, continue, and return statements to control execution flow.


7. Key Takeaways

  • for...of iterates 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 use break and continue inside a for...of loop.
  • It is generally the preferred, modern way to write a standard loop.
Built with LogoFlowershow