Domina los protocolos detrás de for...of, la propagación y la desestructuración, y luego usa generadores para producir secuencias perezosas.
Abrir esta lección en KodokonDos protocolos distintos rigen la iteración. Un objeto es iterable si expone un método bajo la clave Symbol.iterator; ese método debe devolver un iterador, es decir, un objeto con un método next() que devuelve { value, done }. Todo lo que consume secuencias - for...of, el operador de propagación ..., la desestructuración, Array.from, Promise.all - pasa por estos protocolos. Por lo tanto, puedes hacer que cualquier objeto sea compatible.
const range = {
from: 1,
to: 3,
[Symbol.iterator]() {
let current = this.from;
const last = this.to;
return {
next() {
return current <= last
? { value: current++, done: false }
: { value: undefined, done: true };
}
};
}
};
console.log([...range]); // [1, 2, 3]Escribir iteradores a mano es verboso. Los generadores (function*) producen un iterador automáticamente: cada yield suspende la ejecución y preserva el estado local de la función. Esta evaluación perezosa te permite modelar secuencias infinitas, siempre que un consumidor limite el número de valores solicitados.
function* naturals() {
let n = 0;
while (true) yield n++;
}
function* take(iterable, count) {
let index = 0;
for (const value of iterable) {
if (index >= count) return;
yield value;
index += 1;
}
}
console.log([...take(naturals(), 4)]); // [0, 1, 2, 3]Los iteradores de generador también exponen return() y throw(). Un detalle de la especificación que a menudo pasa desapercibido: cuando abandonas un bucle for...of con break, return o una excepción, el motor llama automáticamente a iterator.return(). En un generador, eso ejecuta cualquier bloque finally pendiente - el lugar ideal para liberar un recurso (un archivo, una conexión, un bloqueo).
function* readLines() {
try {
yield "line 1";
yield "line 2";
} finally {
console.log("cleanup");
}
}
for (const line of readLines()) {
console.log(line);
break; // triggers return(), hence the finally
}
// line 1, cleanuplength e índices numéricosSymbol.iterator que devuelve un objeto con next()Array.prototypenext() directamentefor...of con break mientras consume un generador?throw() sobre el iteradorreturn(), que ejecuta los bloques finally del generadornext()