Iterables and Generators
From Symbols To Iteration
In our last lesson, we explored how Symbols act as unique keys for object properties. We also saw that Well-Known Symbols allow us to change how JavaScript handles our objects behind the scenes. This lesson builds directly on that idea. We are going to look at one of the most powerful Well-Known Symbols: Symbol.iterator.
By the end of this lesson, you will know how to take a standard JavaScript class and make it "iterable." This means your custom objects will gain the ability to work with common tools like for...of loops, the spread operator, and array destructuring. Just like Symbol.toPrimitive helped us control how an object becomes a number or string, Symbol.iterator helps us control how an object shares its data one piece at a time.
The Iteration Protocol
JavaScript has a set of rules called the Iteration Protocol. For an object to be used in a loop like for...of, it must follow these rules. Specifically, the object needs a method named Symbol.iterator. When you try to loop over an object, JavaScript looks for this "magic" symbol key. If it finds it, the engine calls that method to get an iterator.
Think of an iterator as a specialized pointer that knows how to move through a collection of data. This protocol is what makes arrays and strings work with loops automatically. By adding this symbol to your own objects, you are telling the JavaScript engine that your object is now a collection that can be stepped through. This makes your custom code feel like a built-in part of the language.
Building A Custom Iterable Class
Let's look at how to implement this in a real class. Imagine we have a TransactionLog that stores several transactions. We want to be able to loop through these entries easily. In the example below, we use a private field called #entries to store our data and then define the iterator method.
In this code, the asterisk * before the [Symbol.iterator] name tells JavaScript that this is a generator method. Inside the method, we use the yield keyword. You can think of yield as a way to pause the function and hand out a value. When the loop asks for the next item, the function resumes exactly where it left off until it hits the next yield. This is much simpler than manually tracking index numbers.
