Lección 7 · 7 de 20
Iteradores y generadores · JavaScript
Cree secuencias bajo demanda en JavaScript con function* y yield, y haga sus objetos recorribles con for...of mediante Symbol.iterator.

Una función generadora se declara con function* y, en vez de devolver un valor y terminar, se pausa en cada yield. Llamar a invoiceNumbers("INV", 7) no ejecuta nada todavía: devuelve un generador. Cada next() reanuda el código hasta el siguiente yield y entrega un objeto { value, done }, como muestra la tercera línea de la salida.
Por eso un generador puede ser infinito sin bloquear el programa: el bucle for sin condición de invoiceNumbers solo avanza cuando alguien pide otro número. Es una forma cómoda de producir valores bajo demanda: numeraciones, páginas de una API o líneas de un fichero.
El protocolo de iteración es lo que usan for...of, el operador ... y la desestructuración: piden al objeto su método [Symbol.iterator](). Playlist lo define como generador (*[Symbol.iterator]()), así que sus canciones se recorren con for...of y se copian a un array con [...party].
countdown muestra lo que hay debajo, sin generadores: un iterador es simplemente un objeto con un método next() que devuelve { value, done }. Cuando done es true, el recorrido termina. Como [Symbol.iterator]() devuelve this, el objeto es a la vez iterable e iterador.
Código · main.js
// A generator pauses at each yield and resumes on the next call to next().function* invoiceNumbers(prefix, start) { for (let n = start; ; n++) { yield `${prefix}-${String(n).padStart(4, "0")}`; }}const numbers = invoiceNumbers("INV", 7);console.log(numbers.next().value);console.log(numbers.next().value);console.log(numbers.next());// Any object with [Symbol.iterator] works with for...of and spread.class Playlist { constructor(...songs) { this.songs = songs; } *[Symbol.iterator]() { for (const song of this.songs) yield song.toUpperCase(); }}const party = new Playlist("intro", "hit single", "encore");for (const song of party) console.log("Playing", song);console.log([...party].length, "songs in the playlist");// A hand-written iterator: an object whose next() returns { value, done }.function countdown(from) { let current = from; return { [Symbol.iterator]() { return this; }, next: () => (current > 0 ? { value: current--, done: false } : { value: undefined, done: true }), };}console.log("Launch in", [...countdown(3)].join(", "));Salida · node main.js
INV-0007
INV-0008
{ value: 'INV-0009', done: false }
Playing INTRO
Playing HIT SINGLE
Playing ENCORE
3 songs in the playlist
Launch in 3, 2, 1Para recordar
function*define un generador;yieldentrega un valor y pausa.- Cada
next()devuelve{ value, done }. - Un generador puede ser infinito porque solo calcula lo que se le pide.
- Un objeto con
[Symbol.iterator]()funciona confor...ofy con....
Ejercicio
Escriba un generador take(iterable, n) que entregue solo los n primeros valores de otro iterable, y úselo para obtener cinco números de factura con [...take(invoiceNumbers("INV", 1), 5)].