Generators

Generators are functions that can be paused and resumed using yield. They return an iterator that produces values on demand.

Basic Generator

function* myGenerator() {
  yield 0;
  yield 1;
  yield 2;
  yield 3;
}

const gen = myGenerator();
console.log(gen.next()); // { value: 0, done: false }
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 }

Dynamic Range Generator

function* rangeGenerator(start: number, end: number) {
  while (start <= end) yield start++;
}

console.log([...rangeGenerator(0, 3)]); // [0, 1, 2, 3]
console.log([...rangeGenerator(5, 10)]); // [5, 6, 7, 8, 9, 10]

Iterators

An iterator is an object that follows the Iterator Protocol: it has a next() method returning { value, done }.

Basic Iterator

const myIterator = {
  current: 0,
  last: 3,
  next() {
    return this.current <= this.last
      ? { value: this.current++, done: false }
      : { done: true };
  }
};

console.log(myIterator.next()); // { value: 0, done: false }
console.log(myIterator.next()); // { value: 1, done: false }
console.log(myIterator.next()); // { value: 2, done: false }
console.log(myIterator.next()); // { value: 3, done: false }
console.log(myIterator.next()); // { done: true }

Iterable Iterator (Supports for...of)

const createIterator = (start: number, end: number) => ({
  current: start,
  last: end,
  next() {
    return this.current <= this.last
      ? { value: this.current++, done: false }
      : { done: true };
  },
  [Symbol.iterator]() {
    return this;
  }
});

console.log([...createIterator(0, 3)]); // [0, 1, 2, 3]
console.log([...createIterator(5, 10)]); // [5, 6, 7, 8, 9, 10]

Comparison: Generator vs Iterator

Feature Generators Iterators
Syntax function* with yield Object with next()
Lazy Evaluation Automatic (pause/resume with yield) Manual (explicit control with next())
Iterable (for...of) Yes (automatically iterable) No, unless Symbol.iterator is implemented
State Management Automatic (execution state is saved internally) Manual (must track current state)
Best Use Case Lazy iteration, streaming data, async operations Custom iteration behavior, strict control over state