JavaScript
Creating a custom iterator
Learn to create a custom iterator by adding Symbol.iterator to an object.
Creating a custom iterator
To write your own iterator, you add [Symbol.iterator] to an object. Inside the method you declare a state variable with let; it remembers where you are in the loop. The inner object you return has a next() method that reads and advances this variable.
This pattern is a stateful iterator. The state variable is created when [Symbol.iterator] is called; each loop has its own state. That lets you traverse the same iterable multiple times independently.
State with closure
A variable declared with let inside [Symbol.iterator] is captured by closure in the returned iterator's next() method. Each next() call reaches the same variable and updates it; that is how the state advances step by step.
Every [Symbol.iterator] call creates a fresh let. So two iterators taken from the same iterable do not affect each other. This is a critical distinction for independent loops.
Exercise Number range iterable
Create an object called range with from and to properties (e.g. 1 and 5). Add a [Symbol.iterator] method. Inside the method, initialize the state with let current = this.from;. The returned iterator's next() method should return { value: current++, done: false } while current <= this.to, otherwise { value: undefined, done: true }. Then loop over the numbers with for...of and log each with console.log.
Show example solution
const range = {
from: 1,
to: 5,
[Symbol.iterator]() {
let current = this.from;
const to = this.to;
return {
next() {
if (current <= to) {
return { value: current++, done: false };
}
return { value: undefined, done: true };
}
};
}
};
for (const num of range) {
console.log(num);
}
Test yourself
-
What should [Symbol.iterator] return in a custom iterator?
- An iterator object (with a next method)
- A number
- An array
- A string
Show answer
An iterator object (with a next method) — Correct. [Symbol.iterator] returns an iterator with a next() method.
-
Declare the state variable
const range = {
from: 1,
to: 5,
[Symbol.iterator]() {
____
return {
next() {
if (this.to >= current) {
return { value: current++, done: false };
}
return { done: true };
}
};
}
};
Show answer
const range = {
from: 1,
to: 5,
[Symbol.iterator]() {
let current = this.from;
return {
next() {
if (this.to >= current) {
return { value: current++, done: false };
}
return { done: true };
}
};
}
};
-
Custom iterator concepts
- [Symbol.iterator]
- Method that produces an iterator
- let current
- State held by closure
- next()
- Advances one step
- done: true
- Exhaustion signal
Next lesson: Common iterables