07 / 20 · Day 3
Day 3 · Concept 07

Loops & iterators

for-of walks values. for-in walks object keys (rarely what you want). Generators produce iterables lazily. The iterator protocol unifies them all.


1 · for-of — the workhorse

js for-of.js
// Works on anything iterable: arrays, strings, Maps, Sets, etc.
for (const ch of "hi!") {
    console.log(ch);
}

for (const x of [10, 20, 30]) {
    console.log(x);
}

const map = new Map([["a", 1], ["b", 2]]);
for (const [k, v] of map) {
    console.log(k, v);
}

2 · for-in — for object keys only

js for-in.js
const counts = { apples: 3, pears: 5 };

for (const key in counts) {
    console.log(key, counts[key]);
}

// Never use on arrays — returns indices as strings and walks inherited keys
const arr = [10, 20, 30];
for (const i in arr) {
    console.log(typeof i, i);    // "string" "0", etc.
}

The rule: for-of for arrays and iterables; for-in for plain objects only. Or — better — Object.entries(obj) + for-of.

3 · Array.from — turn anything iterable into an array

js from.js
// Generate a sequence
console.log(Array.from({ length: 5 }, (_, i) => i * i));

// Iterable → array
console.log(Array.from("abc"));
console.log(Array.from(new Set([1, 2, 2, 3])));

4 · Generators — lazy iterables

js gen.js
function* fib() {
    let [a, b] = [0, 1];
    while (true) {
        yield a;
        [a, b] = [b, a + b];
    }
}

const it = fib();
const first10 = [];
for (let i = 0; i < 10; i++) first10.push(it.next().value);
console.log(first10);

The function* + yield pair gives you a paused/resumed function. Useful for infinite or expensive sequences.

5 · Common mistakes

  • for-in on arrays. Keys are strings; order is engine-dependent (mostly insertion, but don't rely on it). Use for-of.
  • forEach with await. forEach doesn't await. Use for-of with await inside, or Promise.all.
  • Mutating while iterating. Modifying an array during for-of can skip or repeat elements. Collect indices first or use a copy.

6 · When it clicks

  • for-of for sequences; Object.entries for objects; .map/.filter/.reduce when you can.
  • Array.from({length: n}, ...) for generating ranges.
  • Generators are second nature for stream-like data.
Found this useful?