CodeBlanks Logo Icon CodeBlanks

Creating a custom iterator

JavaScript course · Advanced · Lesson 45/100

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

  1. 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.

  2. 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 };
          }
        };
      }
    };
  3. Custom iterator concepts

    [Symbol.iterator]
    Method that produces an iterator
    let current
    State held by closure
    next()
    Advances one step
    done: true
    Exhaustion signal

All lessons in Advanced