JavaScript Generators
In this section, we'll explore JavaScript generators—a powerful feature that helps you create memory-efficient iterators. Generators allow you to iterate over data lazily, especially useful when dealing with large datasets or infinite sequences. Let's dive into the syntax, how to create a generator, and practical usage examples.
Quick Links
Understanding Generator Syntax
A generator in JavaScript is a special function that can be paused and resumed. It is defined using the function* syntax, where the asterisk indicates that the function is a generator. The yield keyword is used to pause the function and send a value to the caller.
function* myGenerator() {
yield 1;
yield 2;
yield 3;
}
const gen = myGenerator(); // Create generator object
console.log(gen.next().value); // Output: 1
console.log(gen.next().value); // Output: 2
console.log(gen.next().value); // Output: 3
function* myGenerator() {
yield 1;
yield 2;
yield 3;
}
const gen = myGenerator(); // Create generator object
console.log(gen.next().value); // Output: 1
console.log(gen.next().value); // Output: 2
console.log(gen.next().value); // Output: 3
In this example, myGenerator is a generator function that yields values one at a time. The next() method is used to retrieve the next value from the generator.
Using the yield Keyword
The yield keyword pauses the function’s execution and sends a value back to the caller. The function retains its state, so when you call next() again, it continues where it left off.
function* countUpTo(max) {
let count = 1;
while (count <= max) {
yield count;
count++;
}
}
const counter = countUpTo(5);
console.log(counter.next().value); // Output: 1
console.log(counter.next().value); // Output: 2
function* countUpTo(max) {
let count = 1;
while (count <= max) {
yield count;
count++;
}
}
const counter = countUpTo(5);
console.log(counter.next().value); // Output: 1
console.log(counter.next().value); // Output: 2
In this example, the countUpTo generator yields numbers from 1 up to the specified maximum. Each time next() is called, the function resumes from where it last yielded.
Using yield in Loops
A generator can be used inside loops to yield multiple values in sequence. This makes it especially efficient when iterating over large datasets.
function* evenNumbers(limit) {
for (let number = 2; number <= limit; number += 2) {
yield number;
}
}
for (const even of evenNumbers(10)) {
console.log(even);
}
// Output:
// 2
// 4
// 6
// 8
function* evenNumbers(limit) {
for (let number = 2; number <= limit; number += 2) {
yield number;
}
}
for (const even of evenNumbers(10)) {
console.log(even);
}
// Output:
// 2
// 4
// 6
// 8
This example defines a generator that yields even numbers up to a specified limit. Using a for...of loop, the generator is iterated over efficiently.
Example 1: Fibonacci Sequence Generator
The Fibonacci sequence is a series of numbers where each number is the sum of the two preceding ones. Below is a generator function that yields values from the Fibonacci sequence:
function* fibonacci(n) {
let a = 0, b = 1;
for (let i = 0; i < n; i++) {
yield a;
[a, b] = [b, a + b];
}
}
for (const num of fibonacci(10)) {
console.log(num);
}
function* fibonacci(n) {
let a = 0, b = 1;
for (let i = 0; i < n; i++) {
yield a;
[a, b] = [b, a + b];
}
}
for (const num of fibonacci(10)) {
console.log(num);
}
How It Works:
- function* fibonacci(n): defines a generator function that takes one parameter, n, which specifies how many Fibonacci numbers to generate.
- let a = 0, b = 1; initializes the first two numbers in the sequence.
- yield a; yields the current value of a each iteration.
- [a, b] = [b, a + b]; updates the values to the next pair in the sequence.
- for (const num of fibonacci(10)): loops through the first 10 numbers of the Fibonacci sequence and prints each one.
Output:
0
1
1
2
3
5
8
13
21
34
0
1
1
2
3
5
8
13
21
34
Example 2: Squares of Numbers Generator
This generator yields the square of each number from 1 up to a given limit. It's a simple way to understand how yield works with mathematical operations.
function* squareNumbers(n) {
for (let i = 1; i <= n; i++) {
yield i * i;
}
}
for (const square of squareNumbers(5)) {
console.log(square);
}
function* squareNumbers(n) {
for (let i = 1; i <= n; i++) {
yield i * i;
}
}
for (const square of squareNumbers(5)) {
console.log(square);
}
How It Works:
- function* squareNumbers(n): defines a generator function that takes a single argument n.
- for (let i = 1; i <= n; i++): uses a loop to iterate from 1 to n.
- yield i * i; yields the square of each number from 1 to n.
- for (const square of squareNumbers(5)): prints the squares of numbers from 1 to 5.
Output:
1
4
9
16
25
1
4
9
16
25
Frequently Asked Questions
What is a generator in JavaScript?
What is a generator in JavaScript?
A generator in JavaScript is a special function defined using function*. It can pause its execution using yield and resume later. This helps in managing sequences and efficient data processing.
How is a generator different from a regular function?
How is a generator different from a regular function?
Regular functions run from start to finish. Generators, on the other hand, can pause using yield and continue execution with next(), allowing lazy evaluation.
What does the yield keyword do?
What does the yield keyword do?
yield pauses the generator and sends a value to the caller. When next() is called again, it resumes from where it left off.
Can generators be used in loops?
Can generators be used in loops?
Yes! You can use generators inside for...of loops to iterate through all yielded values. This makes them perfect for working with sequences or large datasets.
What are some practical uses of generators?
What are some practical uses of generators?
Generators can be used for things like generating Fibonacci sequences, looping over large or infinite datasets, lazy-loading items, and even simplifying asynchronous code using async function*.
What’s Next?
Next, you'll explore JavaScript Closures — an essential concept that allows functions to remember the scope in which they were created. Understanding closures is key to mastering more advanced JavaScript.