An is an object with a method returning . An object is if it has a method — that's what makes and spread work. A () is a convenient way to create iterators that can with .
An is an object with a method returning . An object is if it has a method — that's what makes and spread work. A () is a convenient way to create iterators that can with .
next(){ value, done }[Symbol.iterator]for...offunction*yieldfunction* idGenerator() {
let id = 1;
while (true) { // infinite, but lazy — only computes on demand
yield id++; // pause here, return a value, resume on next()
}
}
const gen = idGenerator();
gen.next().value; // 1
gen.next().value; // 2 — execution resumed where it paused
The key idea: execution suspends at each yield and resumes on the next .next(), preserving local state between calls. Nothing is computed until you ask for it.
// process a huge/infinite sequence without building it all in memory
function* take(iterable, n) {
let i = 0;
for (const x of iterable) {
if (i++ >= n) return;
yield x;
}
}
[...take(idGenerator(), 3)]; // [1, 2, 3] — from an infinite generator
const range = {
from: 1, to: 3,
*[Symbol.iterator]() { for (let i = this.from; i <= this.to; i++) yield i; },
};
[...range]; // [1, 2, 3] — works with for...of and spread
Generators enable lazy/infinite sequences, custom iteration, and memory-efficient streaming.
They were also the basis of early async libraries (co) and underpin async iteration (for await...of).
The iterator protocol is what unifies for...of, spread, and destructuring across arrays, Maps, Sets, and strings.