CPCODELAB
JavaScript

Iterators and Generators

13 min read

The Iteration Protocol

JavaScript defines a standard iteration protocol that any object can implement. An object is iterable if it has a [Symbol.iterator] method that returns an iterator — an object with a next() method returning { value, done } pairs. Arrays, strings, Sets, and Maps are iterable by default.

js
// Custom iterable: a range of numbers
function range(start, end) {
  return {
    [Symbol.iterator]() {
      let current = start;
      return {
        next() {
          if (current <= end) {
            return { value: current++, done: false };
          }
          return { value: undefined, done: true };
        }
      };
    }
  };
}

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

Generator Functions

Generator functions (declared with function*) are a concise way to write iterators. Each yield expression pauses execution and produces a value. The function resumes from where it left off on the next call to next().

js
function* range(start, end) {
  for (let i = start; i <= end; i++) {
    yield i;
  }
}

const gen = range(1, 3);
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }

// Works with all iterable consumers
console.log([...range(1, 5)]); // [1,2,3,4,5]

Infinite Sequences and Lazy Evaluation

Generators are lazy — they compute values on demand. This makes it practical to represent infinite sequences without running out of memory.

js
function* naturals() {
  let n = 1;
  while (true) yield n++; // infinite!
}

function take(n, iter) {
  const result = [];
  for (const v of iter) {
    result.push(v);
    if (result.length === n) break;
  }
  return result;
}

take(5, naturals()); // [1, 2, 3, 4, 5]

Generators also power async generators (async function*) which yield Promises, enabling streaming data consumption with for await...of. This pattern is used in Node.js streams and the Web Streams API.

Ready to test yourself?
Practice JavaScript— quiz & coding exercises