What are iterators and generators?
By FrontendPro Editorial Team Updated 9/26/2026
Answer
An iterator is any object with a next() method returning { value, done }. An object becomes iterable — usable with for...of and spread — when it has a [Symbol.iterator] method returning such an iterator.
const range = {
from: 1, to: 3,
[Symbol.iterator]() {
let n = this.from, last = this.to;
return { next: () => (n <= last ? { value: n++, done: false } : { value: undefined, done: true }) };
},
};
[...range]; // [1, 2, 3]
Arrays, strings, Map, Set and NodeList all implement this, which is why they work with for...of while a plain object does not.
Generators write iterators for you
A function* returns an iterator automatically. yield produces a value and pauses; the function resumes where it left off on the next call:
function* range(from, to) {
for (let n = from; n <= to; n++) yield n;
}
[...range(1, 3)]; // [1, 2, 3]
The same logic, without hand-writing the protocol.
Laziness is the real point
Values are produced on demand, so a sequence can be infinite and you only pay for what you consume:
function* ids() { let i = 0; while (true) yield i++; }
const gen = ids();
gen.next().value; // 0
gen.next().value; // 1 — nothing precomputed
This lets you process a huge file or a paginated API one item at a time without holding it all in memory.
Where you meet them
for...of, spread, destructuring and yield* delegation all run on this protocol. Redux Saga built its control flow on generators, and async function* plus for await...of is how you stream chunks from a fetch response body.
In everyday application code you will consume iterators constantly and write generators rarely — but knowing the protocol explains why for...of works on some things and not others.
