function*
Baseline
Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since September 2016.
Die function*
Deklaration erstellt eine Bindung einer neuen Generatorfunktion zu einem gegebenen Namen. Eine Generatorfunktion kann beendet und später wieder betreten werden, wobei ihr Kontext (Variablenbindungen) zwischen den Aufrufen gespeichert wird.
Sie können Generatorfunktionen auch mit dem function*
Ausdruck definieren.
Probieren Sie es aus
function* generator(i) {
yield i;
yield i + 10;
}
const gen = generator(10);
console.log(gen.next().value);
// Expected output: 10
console.log(gen.next().value);
// Expected output: 20
Syntax
function* name(param0) {
statements
}
function* name(param0, param1) {
statements
}
function* name(param0, param1, /* …, */ paramN) {
statements
}
Hinweis: Generatorfunktionen haben keine Entsprechungen als Pfeilfunktionen.
Hinweis:
function
und *
sind getrennte Tokens, sodass sie durch Leerraum oder Zeilenumbrüche getrennt werden können.
Parameter
name
-
Der Funktionsname.
param
Optional-
Der Name eines formalen Parameters für die Funktion. Für die Syntax der Parameter, siehe die Funktionen-Referenz.
statements
Optional-
Die Anweisungen, die den Körper der Funktion bilden.
Beschreibung
Eine function*
Deklaration erstellt ein GeneratorFunction
Objekt. Jedes Mal, wenn eine Generatorfunktion aufgerufen wird, gibt sie ein neues Generator
Objekt zurück, das dem Iterator-Protokoll entspricht. Die Ausführung der Generatorfunktion wird an einem Punkt unterbrochen, der anfänglich ganz am Anfang des Funktionskörpers liegt. Die Generatorfunktion kann mehrfach aufgerufen werden, um mehrere Generatoren gleichzeitig zu erstellen; jeder Generator behält seinen eigenen Ausführungskontext der Generatorfunktion und kann unabhängig durchlaufen werden.
Der Generator ermöglicht einen bidirektionalen Kontrollfluss: Der Kontrollfluss kann beliebig oft zwischen der Generatorfunktion (callee) und ihrem Aufrufer hin- und herwechseln, solange beide Parteien dies wünschen. Der Kontrollfluss kann vom Aufrufer zum Callee durch das Aufrufen der Methoden des Generators übertragen werden: next()
, throw()
und return()
. Der Kontrollfluss kann vom Callee zum Aufrufer durch normales Verlassen der Funktion mittels return
oder throw
oder durch Ausführung aller Anweisungen wechseln oder durch die Verwendung der yield
und yield*
Ausdrücke.
Wenn die Methode next()
des Generators aufgerufen wird, wird der Körper der Generatorfunktion bis zu einem der folgenden Punkte ausgeführt:
- Ein
yield
Ausdruck. In diesem Fall gibt dienext()
Methode ein Objekt mit einervalue
Eigenschaft zurück, die den ausgegebenen Wert enthält, und einerdone
Eigenschaft, die immerfalse
ist. Das nächste Mal, wennnext()
aufgerufen wird, wird deryield
Ausdruck zu dem Wert, dernext()
übergeben wird. - Ein
yield*
, das zu einem anderen Iterator delegiert. In diesem Fall entspricht dieser Aufruf und alle zukünftigennext()
Aufrufe auf dem Generator dem Aufruf vonnext()
auf dem delegierten Iterator, bis der delegierte Iterator abgeschlossen ist. - Eine
return
Anweisung (die nicht von einemtry...catch...finally
abgefangen wird), oder das Ende des Kontrollflusses, was implizitreturn undefined
bedeutet. In diesem Fall ist der Generator abgeschlossen, und dienext()
Methode gibt ein Objekt mit einervalue
Eigenschaft zurück, die den Rückgabewert enthält, und einerdone
Eigenschaft, die immertrue
ist. Weiterenext()
Aufrufe haben keine Wirkung und geben immer{ value: undefined, done: true }
zurück. - Ein Fehler, der innerhalb der Funktion geworfen wird, entweder durch eine
throw
Anweisung oder eine nicht behandelte Ausnahme. Die Methodenext()
wirft diesen Fehler, und der Generator ist abgeschlossen. Weiterenext()
Aufrufe haben keine Wirkung und geben immer{ value: undefined, done: true }
zurück.
Wenn die Methode throw()
des Generators aufgerufen wird, wirkt dies, als ob eine throw
Anweisung an der aktuellen unterbrochenen Position im Körper des Generators eingefügt wird. Ebenso wenn die Methode return()
des Generators aufgerufen wird, wirkt dies, als ob eine return
Anweisung an der aktuellen unterbrochenen Position im Körper des Generators eingefügt wird. Beide Methoden beenden normalerweise den Generator, es sei denn, die Generatorfunktion fängt die Beendigung durch try...catch...finally
ab.
Generatoren wurden früher als Paradigma für asynchrones Programmieren verwendet, um Callback Hell durch das Erreichen der Umkehrung der Kontrolle zu vermeiden. Heutzutage wird dieser Anwendungsfall mit dem einfacheren Modell der Async-Funktionen und dem Promise
Objekt gelöst. Dennoch sind Generatoren weiterhin nützlich für viele andere Aufgaben, wie zum Beispiel das Definieren von Iteratoren auf einfache Weise.
function*
Deklarationen verhalten sich ähnlich wie function
Deklarationen — sie werden gehoben an die Spitze ihres Gültigkeitsbereichs und können überall in ihrem Gültigkeitsbereich aufgerufen werden, und sie können nur in bestimmten Kontexten neu deklariert werden.
Beispiele
>Einfaches Beispiel
function* idMaker() {
let index = 0;
while (true) {
yield index++;
}
}
const gen = idMaker();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
// …
Beispiel mit yield*
function* anotherGenerator(i) {
yield i + 1;
yield i + 2;
yield i + 3;
}
function* generator(i) {
yield i;
yield* anotherGenerator(i);
yield i + 10;
}
const gen = generator(10);
console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20
Übergabe von Argumenten an Generatoren
function* logGenerator() {
console.log(0);
console.log(1, yield);
console.log(2, yield);
console.log(3, yield);
}
const gen = logGenerator();
// the first call of next executes from the start of the function
// until the first yield statement
gen.next(); // 0
gen.next("pretzel"); // 1 pretzel
gen.next("california"); // 2 california
gen.next("mayonnaise"); // 3 mayonnaise
Rückgabeanweisung in einem Generator
function* yieldAndReturn() {
yield "Y";
return "R";
yield "unreachable";
}
const gen = yieldAndReturn();
console.log(gen.next()); // { value: "Y", done: false }
console.log(gen.next()); // { value: "R", done: true }
console.log(gen.next()); // { value: undefined, done: true }
Generator als Objekteigenschaft
const someObj = {
*generator() {
yield "a";
yield "b";
},
};
const gen = someObj.generator();
console.log(gen.next()); // { value: 'a', done: false }
console.log(gen.next()); // { value: 'b', done: false }
console.log(gen.next()); // { value: undefined, done: true }
Generator als Objektmethode
class Foo {
*generator() {
yield 1;
yield 2;
yield 3;
}
}
const f = new Foo();
const gen = f.generator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
Generator als berechnete Eigenschaft
class Foo {
*[Symbol.iterator]() {
yield 1;
yield 2;
}
}
const SomeObj = {
*[Symbol.iterator]() {
yield "a";
yield "b";
},
};
console.log(Array.from(new Foo())); // [ 1, 2 ]
console.log(Array.from(SomeObj)); // [ 'a', 'b' ]
Generatoren sind nicht konstruierbar
function* f() {}
const obj = new f(); // throws "TypeError: f is not a constructor
Generator-Beispiel
function* powers(n) {
// Endless loop to generate
for (let current = n; ; current *= n) {
yield current;
}
}
for (const power of powers(2)) {
// Controlling generator
if (power > 32) {
break;
}
console.log(power);
// 2
// 4
// 8
// 16
// 32
}
Spezifikationen
Specification |
---|
ECMAScript® 2026 Language Specification> # sec-generator-function-definitions> |
Browser-Kompatibilität
Loading…
Siehe auch
- Leitfaden zu Funktionen
- Leitfaden zu Iteratoren und Generatoren
- Funktionen
GeneratorFunction
function*
Ausdruckfunction
async function
async function*
- Iterationsprotokolle
yield
yield*
Generator
- Regenerator auf GitHub
- Promises and Generators: control flow utopia Präsentation von Forbes Lindesay bei JSConf (2013)
- Task.js auf GitHub
- You Don't Know JS: Async & Performance, Ch.4: Generators von Kyle Simpson