JavaScript Tutorial · JavaScript Toolbox · Lesson 39 of 44

JavaScript Iterators and Generators

Make objects iterable and produce values lazily with generators.

Iterables

Anything you can use in for...of or spread with ... is iterable: arrays, strings, Maps, Sets. Under the hood, it has a [Symbol.iterator]() method that returns an iterator with a next() method.

Generator functions

A function* can yield values one at a time. Calling it returns a generator — an iterator that runs the function only as far as the next yield:

Example 1Try it yourself
function* countdown(from) {
  while (from > 0) {
    yield from;
    from--;
  }
  return "liftoff";
}
const it = countdown(3);
console.log(it.next());
console.log(it.next());
console.log([...countdown(5)]);

Output

{ value: 3, done: false }
{ value: 2, done: false }
[ 5, 4, 3, 2, 1 ]

Lazy and infinite sequences

Because values are produced on demand, generators can describe sequences that never end:

Example 2Try it yourself
function* naturals() {
  let n = 1;
  while (true) yield n++;
}
function* take(iterable, count) {
  for (const value of iterable) {
    if (count-- <= 0) return;
    yield value;
  }
}
console.log([...take(naturals(), 5)]);

Output

[ 1, 2, 3, 4, 5 ]

Making your own class iterable

Example 3Try it yourself
class Range {
  constructor(start, end) {
    this.start = start;
    this.end = end;
  }
  *[Symbol.iterator]() {
    for (let i = this.start; i <= this.end; i++) yield i;
  }
}
const r = new Range(3, 6);
console.log([...r]);
for (const n of new Range(1, 3)) console.log("n =", n);

Output

[ 3, 4, 5, 6 ]
n = 1
n = 2
n = 3

Test yourself

Which keyword pauses a generator and hands out a value?

  1. return
  2. await
  3. yield
  4. pause
Show answer

Answer: yield