Learn iterators, the iteration protocol, and generators for controlling how data is consumed.
next method returning value and done properties.Symbol.iterator to make custom objects natively iterable.yield* to simplify generator loop declarations.Object.entries() before attempting loop iteration over them.Iterator definitionProvides a next method returning value and done flags.
const arr = [10, 20];
const it = arr[Symbol.iterator]();
it.next(); // { value: 10, done: false }Iteration stateTracks progress dynamically, returning done: true when complete.
it.next(); // { value: 20, done: false }
it.next(); // { value: undefined, done: true }Underlying supportPowers loops, spreads, and destructuring operations implicitly.
const [x, y] = [10, 20]; // uses iteratorCustom iterablesImplements Symbol.iterator to make objects work with for-of.
const obj = {
data: [1, 2, 3],
[Symbol.iterator]() {
let i = 0;
return {
next: () => ({
value: this.data[i],
done: i++ >= this.data.length
})
};
}
};
for (const n of obj) console.log(n);Required structuresDemands the standard iterator method shape to match engine interfaces.
// Iterator returns: { next() { ... } }Standard collectionsProvides native iteration for strings, arrays, sets, and maps.
for (const char of "Hi!") console.log(char);
for (const val of new Set([1, 2])) console.log(val);Map entriesIterates over key-value pairs using array destructuring syntax.
const map = new Map([['a', 1]]);
for (const [k, v] of map) console.log(k, v);DOM NodeListsSupports for-of iteration on elements retrieved from DOM queries.
const divs = document.querySelectorAll("div");
for (const div of divs) console.log(div);Generator functionsPauses function execution using the yield keyword.
function* greet() {
const name = yield "name?";
yield `Hello, ${name}!`;
}
const g = greet();
g.next().value; // "name?"
g.next("Ada").value; // "Hello, Ada!"Generator delegationDelegates execution to nested iterables using the yield* operator.
function* combine() {
yield* [1, 2];
yield* ['a', 'b'];
}
console.log([...combine()]); // [1, 2, 'a', 'b']An iterable is an object defining a Symbol.iterator method. An iterator is the returned object containing a next() method. Arrays are iterables, while array.values() returns an iterator.
Yes, define a Symbol.iterator method returning a next() method on your object. That method must return a {value, done} structure. The object then supports for...of loops.
Iterators hold internal state and become exhausted when they return done: true. Calling next() afterward continues returning true. Retrieve a fresh iterator to loop again.
Use generator functions for complex state tracking. The runtime automatically manages state boundaries and suspends executions. Manual iterators are better for highly specific performance scenarios.
Yes, both operations rely on the standard Symbol.iterator protocol. Any object implementing this protocol will work correctly with destructuring and spread operators.
Paginated API Response Iterator
Wraps a paginated server endpoint inside a custom async iterator for streaming record sets.
function createPageIterator(fetcher) {
let nextPage = 1;
let isDone = false;
return {
[Symbol.iterator]() {
return {
async next() {
if (isDone) {
return { done: true };
}
const res = await fetcher(nextPage);
if (res.hasMore) {
nextPage++;
} else {
isDone = true;
}
return { value: res.items, done: false };
}
};
}
};
}Custom iteration protocols allow you to stream paginated datasets as if they were simple local loops.