Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The yield* operator delegates the execution of a generator to another iterable object or generator. When encountered, it pauses the current generator and yields values from the target iterable one by one until the target is exhausted, effectively flattening the iteration process.

Syntax

yield* expression;
  • expression: Any object that implements the iterable protocol (e.g., Generators, Arrays, Strings, Maps, Sets, or custom iterables containing a [Symbol.iterator]() method).

Execution Mechanics

When the JavaScript engine evaluates a yield* expression, it performs the following sequence:
  1. Iterator Instantiation: It calls the [Symbol.iterator]() method on the provided expression to retrieve an iterator.
  2. Value Delegation: It repeatedly calls the next() method on the delegated iterator. For every IteratorResult object returned with done: false, the JavaScript engine extracts the value property and constructs a brand new IteratorResult object to pass to the caller of the outer generator. Any custom properties attached to the inner iterator’s IteratorResult object are lost and not passed to the caller.
  3. Expression Evaluation: When the delegated iterator is exhausted (returns an IteratorResult where done: true), the yield* expression evaluates to the value property of that final IteratorResult.

Return Value Behavior

A critical mechanical distinction between yield and yield* is how the expression itself evaluates within the generator body. While a standard yield evaluates to the argument passed to the outer generator’s next(val) method, a yield* expression evaluates to the explicit return value of the delegated iterator.
function* innerGenerator() {
  yield 'A';
  yield 'B';
  return 'Inner Complete'; // This becomes the evaluation result of yield*
}

function* outerGenerator() {
  yield 'Start';
  
  // The generator pauses here, yielding 'A' and 'B' to the caller.
  // Once innerGenerator finishes, 'Inner Complete' is assigned to innerResult.
  const innerResult = yield* innerGenerator(); 
  
  yield innerResult;
}

const gen = outerGenerator();

console.log(gen.next().value); // 'Start'
console.log(gen.next().value); // 'A' (Delegated)
console.log(gen.next().value); // 'B' (Delegated)
console.log(gen.next().value); // 'Inner Complete' (Evaluated result of yield*)

Method Proxying

The yield* operator does not merely loop over values; it acts as a two-way proxy between the outer generator and the delegated iterator. If the caller invokes next(), throw(), or return() on the outer generator while a yield* expression is active, those method calls (and their arguments) are forwarded directly to the delegated iterator:
  • next(value): The value is passed to the inner iterator’s next() method.
  • throw(error): If the inner iterator has a throw() method, it is called with the error. If it does not have a throw() method, the JavaScript engine throws a TypeError (e.g., “The iterator does not provide a ‘throw’ method”), the inner iterator is closed, and the original error passed to the outer generator is discarded.
  • return(value): If the inner iterator has a return() method, it is called. The IteratorResult returned by the inner iterator’s return() method dictates the final return value of the outer generator. This means the inner iterator can override the value originally passed to the outer generator’s return() call.

Delegation to Built-in Iterables

Because yield* operates on the iterable protocol, it natively unpacks standard JavaScript data structures without requiring an intermediate generator function.
function* unpackIterables() {
  yield* [1, 2];       // Array delegation
  yield* "XY";         // String delegation
  yield* new Set([3]); // Set delegation
}

const iterator = unpackIterables();

console.log([...iterator]); // [1, 2, 'X', 'Y', 3]
Master JavaScript with Deep Grasping Methodology!Learn More