Signatur
Beschreibung
Ein function*-Ausdruck (auch Generator-Funktionsausdruck) erzeugt eine Generatorfunktion, die — anders als normale Funktionen — beim Aufruf nicht sofort vollständig ausgeführt wird. Stattdessen gibt sie ein Generator-Objekt zurück, das das Iterator- und Iterable-Protokoll implementiert. Die Ausführung kann mit yield angehalten und mit .next() schrittweise fortgesetzt werden.
Der Unterschied zur function*-Deklaration liegt darin, dass der Ausdruck an eine Variable zugewiesen oder direkt als Argument übergeben werden kann. Der Name des Ausdrucks ist dabei optional — er ist nur innerhalb des Funktionskörpers (zur Rekursion) sichtbar, nicht im äußeren Scope. Generatorfunktionen eignen sich hervorragend für lazy evaluation, das Erzeugen von Zahlenfolgen, das Implementieren eigener Iteratoren und für Kontrollflussabstraktion (z. B. in Co-Routinen).
Jeder Aufruf der Generatorfunktion erzeugt ein neues, unabhängiges Generator-Objekt. Über .next(wert) kann ein Wert in den Generator hineingegeben und der nächste yield-Wert abgerufen werden. Mit .return(wert) wird der Generator vorzeitig beendet, mit .throw(fehler) wird ein Fehler in den Generator geworfen. Der Generator gilt als erschöpft (done: true), sobald der Funktionskörper endet oder ein return-Statement erreicht wird.
function*-Ausdrücke können nicht mit new aufgerufen werden und sind keine Arrow-Functions — sie haben ein eigenes this. Mit yield* lässt sich an einen anderen Iterable delegieren.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $name | string | Optionaler Name der Generatorfunktion. Nur innerhalb des Funktionskörpers sichtbar (für Rekursion). Wird der Ausdruck einer Variable zugewiesen, ist der Name der Variablenname. | |
| $args | string | Kommagetrennte Liste von Parameternamen. Unterstützt Standardwerte (x = 0), Rest-Parameter (...rest) und Destructuring. |
Rückgabewert
Beim Definieren des Ausdrucks wird ein Function-Objekt zurückgegeben. Beim Aufrufen der erzeugten Generatorfunktion wird ein Generator-Objekt zurückgegeben, das das Iterator- und Iterable-Protokoll implementiert. Jedes .next() liefert ein Objekt der Form { value: any, done: boolean }.
Beispiele
Einfacher Zahlen-Generator als Ausdruck
const range = function* (start, end, step = 1) {
for (let i = start; i <= end; i += step) {
yield i;
}
};
const gen = range(1, 5);
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
// Als Iterable in for...of nutzen
for (const n of range(1, 5, 2)) {
console.log(n);
}
Unendlicher Generator mit yield* Delegierung
// Unendliche Fibonacci-Folge
const fibonacci = function* () {
let [a, b] = [0, 1];
while (true) {
yield a;
[a, b] = [b, a + b];
}
};
// Hilfsgenerator: die ersten n Werte nehmen
const take = function* (iterable, n) {
let count = 0;
for (const value of iterable) {
if (count++ >= n) return;
yield value;
}
};
const first8 = [...take(fibonacci(), 8)];
console.log(first8);
Wert in Generator hineinreichen via .next(wert)
const logger = function* () {
const eingabe1 = yield 'Bitte ersten Wert eingeben:';
console.log('Erhalten:', eingabe1);
const eingabe2 = yield 'Bitte zweiten Wert eingeben:';
console.log('Erhalten:', eingabe2);
return 'Fertig';
};
const gen = logger();
console.log(gen.next().value); // Startet Generator
console.log(gen.next('Hallo').value); // Gibt 'Hallo' als Rückgabe des ersten yield
console.log(gen.next('Welt')); // Gibt 'Welt' als Rückgabe des zweiten yield
// Wichtig · Fallstricke
Fallstricke und Besonderheiten:
- Kein
new: Generatorfunktionen können nicht mitnewaufgerufen werden — es wird einTypeErrorgeworfen. - Kein
yieldin Callbacks:yieldfunktioniert nur direkt im Generatorkörper, nicht in verschachtelten (normalen) Callback-Funktionen. Für Delegation an einen Sub-Iterable stehtyield*bereit. - Kein Arrow-Generator: Es gibt keine
() =>*-Syntax. Generatoren müssen mitfunction*deklariert werden. - Erschöpfung: Ist ein Generator einmal erschöpft (
done: true), liefern weitere.next()-Aufrufe stets{ value: undefined, done: true }. - Fehlerbehandlung: Mit
gen.throw(new Error(...))kann ein Fehler direkt am aktuellenyield-Punkt in den Generator geworfen und dort mittry/catchabgefangen werden. - Performance: Generatoren erzeugen pro
.next()-Aufruf ein neues Ergebnisobjekt — bei sehr häufigen Aufrufen in engen Schleifen kann das relevant sein.