CodeBlanks Logo Icon CodeBlanks

Custom behavior with Symbol.iterator

JavaScript course · Expert · Lesson 39/63

Learn to add custom iteration behavior to an object with Symbol.iterator.

Custom behavior with Symbol.iterator

To make an object usable with for...of, you define the [Symbol.iterator] method. This implements the iteration protocol: the object returns an iterator, and the iterator yields { value, done } at each step.

This is a metaprogramming tool: structures like for...of, spread and Array.from call this method indirectly. You write the method, the engine does the rest.

A range, a word list or a record set can then be traversed like an ordinary array.

The iteration protocol

The iteration protocol has two parts. An iterable is an object with a [Symbol.iterator] method. An iterator is an object with a next() method that returns { value, done } on each call.

A typical pattern: [Symbol.iterator]() { let i = ...; return { next() { ... } }; }. The state i is kept in a closure; each next() call advances it.

When done: true is produced, the loop ends. Calls after that should keep returning the same final result.

Exercise Make a range iterable

Define a range object with from: 1 and to: 3 properties. Add a [Symbol.iterator]() method: initialize let current = this.from, take const last = this.to and return a next() method. next returns { value: current++, done: false } when current <= last, otherwise { value: undefined, done: true }. Finally loop with for (const n of range), push each value to collected and console.log(collected).

Show example solution
const range = {
  from: 1,
  to: 3,
  [Symbol.iterator]() {
    let current = this.from;
    const last = this.to;
    return {
      next() {
        if (current <= last) {
          return { value: current++, done: false };
        }
        return { value: undefined, done: true };
      }
    };
  }
};
const collected = [];
for (const n of range) {
  collected.push(n);
}
console.log(collected);

Test yourself

  1. What should [Symbol.iterator] return?

    • A number
    • An array
    • A string
    • An iterator object with a next method
    Show answer

    An iterator object with a next method — Correct! [Symbol.iterator] must return an iterator with a next() method.

  2. Complete the iterator

    const range = {
      [Symbol.iterator]() {
        let current = 1;
        return {
          ____() {
            return { value: current++, done: false };
          }
        };
      }
    };
    Show answer
    const range = {
      [Symbol.iterator]() {
        let current = 1;
        return {
          next() {
            return { value: current++, done: false };
          }
        };
      }
    };
  3. Match each concept to its role

    next()
    Produces the next value
    done
    Ends the loop
    value
    Step's value
    Symbol.iterator
    Makes iterable

All lessons in Expert