Skip to content

JavaScript Tutorial Iterators and Generators

Creating Your Own Iterable

Lesson 181 of 258 2 min read By Deepak Paswan Updated Oct 4, 2026

To make an object loopable, give it a [Symbol.iterator]() method that returns an iterator.

A range of numbers

script.js
JS
const range = {
  from: 1,
  to: 5,

  [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 };
      }
    };
  }
};

for (const n of range) {
  console.log(n);              // 1, 2, 3, 4, 5
}

console.log([...range]);       // → [1, 2, 3, 4, 5]
console.log(Math.max(...range)); // → 5

Because range follows the protocol, for...of, spread, destructuring and Array.from all work with it.

In a class

script.js
JS
class Playlist {
  #songs = [];

  add(song) {
    this.#songs.push(song);
    return this;
  }

  [Symbol.iterator]() {
    let index = 0;
    const songs = this.#songs;

    return {
      next: () =>
        index < songs.length
          ? { value: songs[index++], done: false }
          : { value: undefined, done: true }
    };
  }
}

const list = new Playlist().add("Song A").add("Song B");

for (const song of list) {
  console.log(song);
}
console.log([...list].length); // → 2

The playlist hides its array (private field) but lets other code loop over it.

A simpler way: return an array’s iterator

script.js
JS
class Team {
  #members = ["Maya", "Arjun"];

  [Symbol.iterator]() {
    return this.#members[Symbol.iterator]();   // reuse the array's iterator
  }
}

console.log([...new Team()]); // → ["Maya", "Arjun"]

Even simpler: a generator

A generator function makes the iterator for you. You will see it in the next lesson: Generators.

script.js
JS
class Team {
  #members = ["Maya", "Arjun"];

  *[Symbol.iterator]() {
    yield* this.#members;
  }
}

console.log([...new Team()]); // → ["Maya", "Arjun"]

Iterable or iterator?

  • An iterable can produce a new iterator each time, so you can loop over it many times (arrays, ranges).
  • An iterator is a one-time cursor. Once it reaches the end, it is finished.

Stopping early

If a loop exits early (break, return, an error), JavaScript calls the iterator’s optional return() method so it can clean up, such as closing a file.

lightbulb
Do you need this?
Most of the time, an array and map/filter are enough. Custom iterables are useful when the data is large, infinite or computed on demand, or when you want to hide how a collection is stored.