JavaScript > ES6 and Beyond > Iterators and Generators > for...of loop
Generators and <code>for...of</code>: Custom Iteration
This snippet demonstrates how to create custom iterables using JavaScript generators, making them compatible with the for...of
loop. Generators provide a powerful way to define sequences of values on demand.
Creating a Generator Function
A generator function is defined using the function*
syntax. The yield
keyword pauses the function's execution and returns a value. Each time the next()
method of the generator object is called (implicitly by the for...of
loop), the function resumes execution from where it left off until the next yield
statement. In this example, the numberGenerator
yields a sequence of numbers from start
to end
, incrementing by step
.
// A generator function that yields a sequence of numbers
function* numberGenerator(start, end, step = 1) {
for (let i = start; i <= end; i += step) {
yield i;
}
}
// Using the generator with for...of
const myNumbers = numberGenerator(1, 10, 2); // Start, End, Step
console.log("Iterating over myNumbers:");
for (const number of myNumbers) {
console.log(number);
}
Custom Iterable Object with Generator
This code demonstrates how to make a custom object iterable. It does this by defining a method with the key Symbol.iterator
which returns a generator function. This generator function yields the elements of the data
array. Now, myCustomObject
can be used with the for...of
loop. The key aspect is the *[Symbol.iterator]()
which is shorthand to declare a generator function as the Symbol.iterator method of the object.
// Custom object that implements the iterable protocol using a generator
const myCustomObject = {
data: ["a", "b", "c"],
*[Symbol.iterator]() {
for (const item of this.data) {
yield item;
}
}
};
console.log("Iterating over myCustomObject:");
for (const item of myCustomObject) {
console.log(item);
}
Concepts Behind the Snippet
Generators allow you to define an iterative algorithm by writing a single function whose execution is not continuous. Generators are special types of functions that maintain their state between executions. The yield
keyword is crucial; it effectively pauses the generator function and sends a value back to the caller. When the generator is iterated again, it resumes from where it left off. This behavior is essential for creating custom iterables.
Real-Life Use Case
Consider a scenario where you need to process a large dataset that doesn't fit into memory. A generator can be used to read and yield data chunks on demand, avoiding memory exhaustion. Another use case is creating infinite sequences, such as a stream of random numbers, which can be consumed by a for...of
loop with a break
condition.
Best Practices
for...of
loop.
Interview Tip
Be prepared to explain how generators work and how they can be used to create custom iterables. Demonstrate your understanding of the yield
keyword and the Symbol.iterator
method. Also, be ready to discuss the benefits of using generators for memory efficiency and creating infinite sequences.
When to Use Them
Use generators when you need to create custom iterables, especially when dealing with large datasets, infinite sequences, or complex iterative algorithms. They provide a cleaner and more memory-efficient way to handle such scenarios compared to traditional approaches.
Memory Footprint
Generators are memory-efficient because they only compute and yield values on demand. This is particularly advantageous when dealing with large datasets that would otherwise require significant memory to store.
Alternatives
next()
method with value
and done
properties), but this is generally more verbose than using generators.
Pros
Cons
FAQ
-
What is the purpose of the
yield
keyword in a generator function?
Theyield
keyword pauses the execution of the generator function and returns a value. The function's state is saved, allowing it to resume execution from where it left off when thenext()
method is called again. -
How do I make a custom object iterable using a generator?
Implement the iterable protocol by defining a method with the keySymbol.iterator
that returns a generator function. This generator function should yield the values you want to iterate over. -
Can I use
break
andcontinue
inside afor...of
loop iterating over a generator?
Yes, you can usebreak
andcontinue
inside afor...of
loop iterating over a generator to control the iteration flow, just as you would with other iterables.