Meistere die Protokolle hinter for...of, Spread und Destrukturierung und nutze dann Generatoren, um lazy Sequenzen zu erzeugen.
Diese Lektion in Kodokon öffnenZwei unterschiedliche Protokolle regeln die Iteration. Ein Objekt ist iterierbar, wenn es eine Methode unter dem Schlüssel Symbol.iterator bereitstellt; diese Methode muss einen Iterator zurückgeben, also ein Objekt mit einer next()-Methode, die { value, done } liefert. Alles, was Sequenzen konsumiert - for...of, der Spread-Operator ..., Destrukturierung, Array.from, Promise.all - läuft über diese Protokolle. Du kannst also jedes beliebige Objekt kompatibel machen.
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]Iteratoren von Hand zu schreiben ist umständlich. Generatoren (function*) erzeugen automatisch einen Iterator: Jedes yield pausiert die Ausführung und bewahrt den lokalen Zustand der Funktion. Diese verzögerte Auswertung (lazy evaluation) erlaubt dir, unendliche Sequenzen zu modellieren, solange ein Konsument die Anzahl der angeforderten Werte begrenzt.
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]Generator-Iteratoren stellen außerdem return() und throw() bereit. Ein oft übersehenes Detail der Spezifikation: Wenn du eine for...of-Schleife mit break, return oder einer Ausnahme verlässt, ruft die Engine automatisch iterator.return() auf. In einem Generator führt das alle ausstehenden finally-Blöcke aus - der ideale Ort, um eine Ressource freizugeben (eine Datei, eine Verbindung, einen Lock).
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-Eigenschaft und numerische Indizes zu habenSymbol.iterator-Methode bereitzustellen, die ein Objekt mit next() zurückgibtArray.prototype zu erbennext()-Methode zu habenfor...of-Schleife mit break verlässt, während sie einen Generator konsumiert?throw() auf dem Iterator aufreturn() auf, was die finally-Blöcke des Generators ausführtnext() aufgerufen wird