JavaScript > ES6 and Beyond > Iterators and Generators > yield keyword
Fibonacci Sequence Generator with Yield
This code snippet demonstrates how to use the yield
keyword in JavaScript to create a generator function that produces Fibonacci numbers on demand. Generators are a powerful way to handle potentially infinite sequences or large datasets efficiently.
Code Snippet
This code defines a generator function named fibonacciGenerator
. It initializes two variables, a
and b
, to 0 and 1 respectively, representing the first two numbers in the Fibonacci sequence. The while (true)
loop ensures that the generator can theoretically produce Fibonacci numbers indefinitely. The yield a;
statement pauses the function's execution and returns the current value of a
. The line [a, b] = [b, a + b];
updates a
and b
to calculate the next Fibonacci number. Finally, a generator object is created using const fib = fibonacciGenerator();
. Each call to fib.next().value
resumes the function, calculates the next Fibonacci number, and returns it.
function* fibonacciGenerator() {
let a = 0;
let b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fib = fibonacciGenerator();
console.log(fib.next().value); // Output: 0
console.log(fib.next().value); // Output: 1
console.log(fib.next().value); // Output: 1
console.log(fib.next().value); // Output: 2
console.log(fib.next().value); // Output: 3
Concepts Behind the Snippet
Generators: Generators are functions that can be paused and resumed, allowing you to produce a sequence of values over time. They don't compute all values upfront, but rather generate them on demand. The Iterators: Generators are a type of iterator. An iterator is an object that defines a sequence and a way to obtain the next value in the sequence. The yield
Keyword: The yield
keyword is the heart of generator functions. It pauses the generator's execution and returns a value to the caller. When next()
is called again on the generator object, execution resumes from the point where it was paused.next()
method is used to retrieve the next value.
Real-Life Use Case Section
Generators are useful in scenarios where you need to process large datasets or infinite sequences without loading the entire data into memory at once. Examples include:async/await
, which builds on generators.
Best Practices
Keep generators focused: Design generators to perform a single, well-defined task, like generating a specific sequence or processing data in a particular way. Handle errors gracefully: Implement error handling within the generator to prevent unexpected crashes. Use descriptive names: Give your generator functions and yielded values meaningful names.
Interview Tip
When discussing generators in interviews, emphasize their memory efficiency, their ability to handle infinite sequences, and their relationship to iterators and asynchronous programming. Be prepared to explain the role of the yield
keyword and the next()
method.
When to Use Them
Use generators when:
Memory Footprint
Generators have a relatively small memory footprint because they only generate values on demand. They don't store the entire sequence in memory, which is particularly advantageous when dealing with large or infinite sequences.
Alternatives
Alternatives to generators include:
Pros
Cons
FAQ
-
What happens when the generator reaches the end of the sequence?
When a generator reaches the end of its sequence (or explicitly returns), thenext()
method returns an object withdone: true
. Thevalue
property will either be the return value (if the generator used areturn
statement) orundefined
. -
Can I pass values into a generator?
Yes, you can pass values into a generator using thenext()
method. The value passed tonext()
becomes the result of theyield
expression within the generator. -
How do I use a generator with a
for...of
loop?
Generators are iterables, so you can directly use them with afor...of
loop:function* numberGenerator(limit) { for (let i = 0; i < limit; i++) { yield i; } }
for (const num of numberGenerator(5)) { console.log(num); }