JavaScript generators are a flexible tool for creating iterators and implementing control flow patterns. By understanding how generators work, you can write more efficient and readable programs.
A generator is a function that returns an iterator object. When you call a generator function, it doesn’t run the code inside the function immediately. Instead, it returns an iterator object that you can use to control the generator’s execution. The iterator object has two properties: value
and done
. The value
property is the current value produced by the generator, and the done
property is a boolean that indicates whether the generator has finished executing.
Here’s an example of a generator function that uses the yield
keyword to produce a sequence of values:
function* sequence() {
yield 1;
yield 2;
yield 3;
}
const generator = sequence();
console.log(generator.next().value); // 1
console.log(generator.next().value); // 2
console.log(generator.next().value); // 3
console.log(generator.next().done); // true
In this example, the generator produces a sequence of numbers. You can use the next()
method to iterate through the sequence. The done
property is true
after the final next()
call because the generator has finished executing.
Generators can also receive input through the next()
method. Here’s an example of a generator that produces an infinite sequence of numbers but resets the sequence when it receives a value of true
:
function* sequence() {
let i = 0;
while (true) {
const reset = yield i++;
if (reset) {
i = 0;
}
}
}
const generator = sequence();
console.log(generator.next().value); // 0
console.log(generator.next().value); // 1
console.log(generator.next().value); // 2
generator.next(true);
console.log(generator.next().value); // 0
console.log(generator.next().value); // 1
In this example, the generator produces an infinite sequence of numbers. You can use the next()
method to get the next number in the sequence, but you can also send a value back to the generator to reset the sequence.
Another useful feature of generators is the ability to use them to implement custom iterators. Here’s an example of a generator function that creates an iterator over an array of names:
function* nameIterator(names) {
for (const name of names) {
yield name;
}
}
const names = ["Alice", "Bob", "Charlie"];
const iterator = nameIterator(names);
console.log(iterator.next().value); // "Alice"
console.log(iterator.next().value); // "Bob"
console.log(iterator.next().value); // "Charlie"
In this example, the nameIterator
function uses a for...of
loop to iterate over an array of names and yield each name to the iterator. You can use the next()
method to iterate through the names in the array.
As you can see, JavaScript generators are a powerful and flexible tool for implementing control flow patterns and custom iterators in your code. By using generators in your own code, you can create more efficient and readable programs.