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:
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:
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
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?
returnawaityieldpause
Show answer
Answer: yield