yield*
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.
Der yield*
-Operator kann innerhalb von Generatorfunktionen (synchron oder asynchron) verwendet werden, um an ein anderes iterierbares Objekt, wie zum Beispiel einen Generator
, zu delegieren. Innerhalb asynchroner Generatorfunktionen kann er zusätzlich verwendet werden, um an ein weiteres asynchrones iterierbares Objekt, wie einen AsyncGenerator
, zu delegieren.
Probieren Sie es aus
function* func1() {
yield 42;
}
function* func2() {
yield* func1();
}
const iterator = func2();
console.log(iterator.next().value);
// Expected output: 42
Syntax
yield* expression
Parameter
expression
Optional-
Ein iterierbares Objekt.
Rückgabewert
Gibt den Wert zurück, der von diesem Iterator zurückgegeben wird, wenn er geschlossen wird (wenn done
true
ist).
Beschreibung
Der yield*
-Ausdruck iteriert über den Operanden und yieldet jeden von ihm zurückgegebenen Wert. Er delegiert die Iteration des aktuellen Generators an einen zugrunde liegenden Iterator — die wir im Folgenden als "Generator" und "Iterator" bezeichnen werden. yield*
holt zunächst den Iterator vom Operanden, indem die [Symbol.iterator]()
-Methode des letzteren aufgerufen wird. Dann, jedes Mal, wenn die next()
-Methode des Generators aufgerufen wird, ruft yield*
die next()
-Methode des Iterators auf, übergibt das vom Generator mit next()
empfangene Argument (immer undefined
beim ersten Aufruf), und yieldet dasselbe Ergebnisobjekt wie das, was von der next()
-Methode des Iterators zurückgegeben wird. Wenn das Iterator-Ergebnis done: true
hat, dann hört der yield*
-Ausdruck auf zu laufen und gibt den value
dieses Ergebnisses zurück.
Der yield*
-Operator leitet auch die throw()
- und return()
-Methoden des aktuellen Generators an den zugrunde liegenden Iterator weiter. Wenn der aktuelle Generator vorzeitig durch eine dieser Methoden geschlossen wird, wird der zugrunde liegende Iterator informiert. Wenn die throw()
/return()
-Methode des Generators aufgerufen wird, wird die throw()
/return()
-Methode des zugrunde liegenden Iterators mit demselben Argument aufgerufen. Der Rückgabewert von throw()
/return()
wird ähnlich wie das Ergebnis der next()
-Methode behandelt, und wenn die Methode wirft, wird die Ausnahme vom yield*
-Ausdruck weitergegeben.
Falls der zugrunde liegende Iterator keine return()
-Methode besitzt, wird der yield*
-Ausdruck in eine return
-Anweisung umgewandelt, ebenso als würde return()
auf einem angehaltenen yield
-Ausdruck aufgerufen.
Falls der zugrunde liegende Iterator keine throw()
-Methode besitzt, führt dies dazu, dass yield*
einen TypeError
wirft – doch bevor der Fehler geworfen wird, wird die return()
-Methode des zugrunde liegenden Iterators aufgerufen, falls eine existiert.
Beispiele
Delegieren an einen anderen Generator
Im folgenden Code werden Werte, die von g1()
yielded werden, von next()
-Aufrufen genauso zurückgegeben wie diejenigen, die von g2()
yielded werden.
function* g1() {
yield 2;
yield 3;
yield 4;
}
function* g2() {
yield 1;
yield* g1();
yield 5;
}
const gen = g2();
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: 4, done: false}
console.log(gen.next()); // {value: 5, done: false}
console.log(gen.next()); // {value: undefined, done: true}
Andere iterierbare Objekte
Neben Generator-Objekten kann yield*
auch andere Arten von Iterables yielden (z. B. Arrays, Strings oder arguments
-Objekte).
function* g3(...args) {
yield* [1, 2];
yield* "34";
yield* args;
}
const gen = g3(5, 6);
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: "4", done: false}
console.log(gen.next()); // {value: 5, done: false}
console.log(gen.next()); // {value: 6, done: false}
console.log(gen.next()); // {value: undefined, done: true}
Der Wert des yield* Ausdrucks selbst
yield*
ist ein Ausdruck, keine Anweisung, daher wird er zu einem Wert ausgewertet.
function* g4() {
yield* [1, 2, 3];
return "foo";
}
function* g5() {
const g4ReturnValue = yield* g4();
console.log(g4ReturnValue); // 'foo'
return g4ReturnValue;
}
const gen = g5();
console.log(gen.next()); // {value: 1, done: false}
console.log(gen.next()); // {value: 2, done: false}
console.log(gen.next()); // {value: 3, done: false} done is false because g5 generator isn't finished, only g4
console.log(gen.next()); // {value: 'foo', done: true}
Verwendung mit asynchronen Generatoren
async function* g1() {
await Promise.resolve(0);
yield "foo";
}
function* g2() {
yield "bar";
}
async function* g3() {
// Can use yield* on both async and sync iterators
yield* g1();
yield* g2();
}
const gen = g3();
console.log(await gen.next()); // {value: "foo", done: false}
console.log(await gen.next()); // {value: "bar", done: false}
console.log(await gen.next()); // {done: true}
Methodenweiterleitung
Die next()
, throw()
, und return()
-Methoden des aktuellen Generators werden alle an den zugrunde liegenden Iterator weitergeleitet.
const iterable = {
[Symbol.iterator]() {
let count = 0;
return {
next(v) {
console.log("next called with", v);
count++;
return { value: count, done: false };
},
return(v) {
console.log("return called with", v);
return { value: "iterable return value", done: true };
},
throw(v) {
console.log("throw called with", v);
return { value: "iterable thrown value", done: true };
},
};
},
};
function* gf() {
yield* iterable;
return "gf return value";
}
const gen = gf();
console.log(gen.next(10));
// next called with undefined; the argument of the first next() call is always ignored
// { value: 1, done: false }
console.log(gen.next(20));
// next called with 20
// { value: 2, done: false }
console.log(gen.return(30));
// return called with 30
// { value: 'iterable return value', done: true }
console.log(gen.next(40));
// { value: undefined, done: true }; gen is already closed
const gen2 = gf();
console.log(gen2.next(10));
// next called with undefined
// { value: 1, done: false }
console.log(gen2.throw(50));
// throw called with 50
// { value: 'gf return value', done: true }
console.log(gen.next(60));
// { value: undefined, done: true }; gen is already closed
Falls die return()
/throw()
-Methode des zugrunde liegenden Iterators done: false
zurückgibt, wird der aktuelle Generator weiter ausgeführt und yield*
delegiert weiterhin an den zugrunde liegenden Iterator.
const iterable = {
[Symbol.iterator]() {
let count = 0;
return {
next(v) {
console.log("next called with", v);
count++;
return { value: count, done: false };
},
return(v) {
console.log("return called with", v);
return { value: "iterable return value", done: false };
},
};
},
};
function* gf() {
yield* iterable;
return "gf return value";
}
const gen = gf();
console.log(gen.next(10));
// next called with undefined
// { value: 1, done: false }
console.log(gen.return(20));
// return called with 20
// { value: 'iterable return value', done: false }
console.log(gen.next(30));
// { value: 2, done: false }; gen is not closed
Falls der zugrunde liegende Iterator keine throw()
-Methode hat und die throw()
-Methode des Generators aufgerufen wird, wirft yield*
einen Fehler.
const iterable = {
[Symbol.iterator]() {
let count = 0;
return {
next(v) {
count++;
return { value: count, done: false };
},
};
},
};
function* gf() {
yield* iterable;
return "gf return value";
}
const gen = gf();
gen.next(); // First next() starts the yield* expression
gen.throw(20); // TypeError: The iterator does not provide a 'throw' method.
Spezifikationen
Specification |
---|
ECMAScript® 2026 Language Specification # sec-generator-function-definitions-runtime-semantics-evaluation |