JS Iterators Protocol
In this page:
const iterable = {
[Symbol.iterator]() {
return {
next() {
return { value: value, done: false };
}
};
}
};
What Is an Iterator?
An iterator is an object that provides values one at a time. It has a next() method.
Arrays, Maps, Sets, and strings are all built-in iterables, which is what lets for...of and the spread operator work uniformly across such different data structures.
Example: What Is an Iterator?
// Declare the constant `arr`, set to `[1, 2, 3]`
// Declare the constant `arr`, set to `[1, 2, 3]`
const arr = [1, 2, 3];
// Declare the constant `iterator`, set to `arr[Symbol.iterator]()`
// Declare the constant `iterator`, set to `arr[Symbol.iterator]()`
const iterator = arr[Symbol.iterator]();
// Print `iterator.next()` to the console
// Print `iterator.next()` to the console
console.log(iterator.next());
next() Result
The next() method returns an object with value and done properties. done becomes true when iteration ends.
Once done is true, further calls to next() should keep returning { value: undefined, done: true } rather than throwing or restarting the sequence.
Example: next() Result
const arr = ["a"];
const it = arr[Symbol.iterator]();
console.log(it.next()); // { value: "a", done: false }
console.log(it.next()); // { value: undefined, done: true }
Iterable Protocol
An iterable object provides a Symbol.iterator method. Arrays, strings, and maps are common iterables.
This shared protocol is what lets for...of, spread syntax, and destructuring all work on any object that implements it, not just the language's own built-in collections.
Example: Iterable Protocol
// Declare the constant `iterable`; its value is built below
// Declare the constant `iterable`; its value is built below
const iterable = {
[Symbol.iterator]() {
// Declare the variable `i`, set to `0`
// Declare the variable `i`, set to `0`
let i = 0;
// Return `{ next: () => i < 3 ? { value: i++, done: false } : { value: undefined, done: true } }` from this function
// Return `{ next: () => i < 3 ? { value: i++, done: false } : { value: undefined, done: true } }` from this function
return { next: () => i < 3 ? { value: i++, done: false } : { value: undefined, done: true } };
},
};
for (const v of iterable) console.log(v);
Custom Iterator
You can create your own iterator by defining a next() method and returning value and done.
This is the underlying mechanism generators use automatically — writing function* gives you an iterator without manually managing the next()/done bookkeeping yourself.
Example: Custom Iterator
// Define the function `makeIterator` taking `max`
// Define the function `makeIterator` taking `max`
function makeIterator(max) {
// Declare the variable `i`, set to `0`
// Declare the variable `i`, set to `0`
let i = 0;
// Return `{ next: () => i < max ? { value: i++, done: false } : { value: undefined, done: true } }` from this function
// Return `{ next: () => i < max ? { value: i++, done: false } : { value: undefined, done: true } }` from this function
return { next: () => i < max ? { value: i++, done: false } : { value: undefined, done: true } };
}
// Declare the constant `it`, set to `makeIterator(2)`
// Declare the constant `it`, set to `makeIterator(2)`
const it = makeIterator(2);
// Print `it.next(), it.next(), it.next()` to the console
// Print `it.next(), it.next(), it.next()` to the console
console.log(it.next(), it.next(), it.next());
Iterator vs Iterable
An iterator has next(). An iterable has Symbol.iterator that returns an iterator. Some objects can be both.
Knowing this distinction helps when building custom data structures: implement Symbol.iterator (making it iterable) rather than manually exposing a next() method on the object itself.
Example: Iterator vs Iterable
function* gen() { yield 1; }
const g = gen();
console.log(typeof g.next); // iterator: has next()
console.log(typeof g[Symbol.iterator]); // iterable: has Symbol.iterator too
- Returning an object from
next()withoutdoneandvalue, so loops never stop. - Forgetting
[Symbol.iterator]()on a custom object, sofor...ofthrowsTypeError: not iterable. - Confusing an iterable with an iterator, since an iterable produces an iterator and the iterator has
next().
- Closures, hoisting, and
thisexplain how scope and context work in functions. call,apply, andbindcontrolthis, and IIFEs and strict mode shape how code runs.- Generators and the iterator protocol control how values are produced one at a time.
Chapter Quiz — Complete all 8 topics to unlock
0/8 topics done
Complete these topics first: