Generators and iterators
Sequences, paused on demand.
A generator is a function you can pause and resume. It hands back values one at a time, only computing the next when you ask β which makes lazy and even infinite sequences trivial.
The iterator protocol
An iterator is any object with a next() method that returns { value, done }. An iterable is any object exposing a [Symbol.iterator]() that returns such an iterator. for...of, spread, and destructuring all speak this protocol β implement it and your object plugs into all of them for free.
Generators write iterators for you
A function* returns a generator object that is both an iterator and an iterable. Each yield produces a value and pauses execution; the function's local state survives between calls. You almost never hand-roll { value, done } again β you yield and let the runtime build it.
Lazy by construction
Nothing in a generator runs until the first next() (or for...of step), and only as far as the next yield. That laziness is the whole point: you can describe an infinite sequence like the naturals or Fibonacci and pull just the prefix you need with a take helper, computing nothing more.
Delegation and two-way flow
yield* delegates to another iterable, flattening nested generators without manual loops. And yield is an expression: the value passed to .next(value) becomes the result of the paused yield, so data flows into a running generator as well as out of it.
Try it 6 examples
A lazy range generator
JSintrofor...of and spread both drive the same generator to produce [0,2,4,6,8] and [1,2,3,4], while the manual next() calls expose the raw protocol β two live values then {"done":true} (the value:undefined is dropped by JSON.stringify).