JavaScript Iterators
Learn iterators, the iteration protocol, and generators for controlling how data is consumed.
TL;DR
- 01Expose a
nextmethod returningvalueanddoneproperties. - 02Implement
Symbol.iteratorto make custom objects natively iterable. - 03Use generator functions to construct custom iterables efficiently.
Tips
- 01Use generator functions to implement the iteration contract automatically without manual state tracking.
- 02Delegate execution to nested iterables using
yield*to simplify generator loop declarations.
Warnings
- 01Remember that exhausted iterators cannot be reused without obtaining a fresh iterator instance.
- 02Convert plain objects using
Object.entries()before attempting loop iteration over them.
What Iterators Are
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 iteratorIteration Protocol
Custom 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() { ... } }Built-in Iterables
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);Generators
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']In Practice
Wraps a paginated server endpoint inside a custom async iterator for streaming record sets.
- 01Set up local trackers for page counts and finished statuses.
- 02Expose the iterator protocol handler method on the container.
- 03Define the async next method structure to request records.
- 04Fetch server data records and adjust page markers recursively.
- 05Return the received records list or done flags.
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 };
}
};
}
};
}FAQ
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.