Generator Methods
When Chapter 8 introduced generators, you learned how to define a generator on an object literal by prepending a star (*
) to the method name. The same syntax works for classes as well, allowing any method to be a generator. Here’s an example:
class MyClass {
*createIterator() {
yield 1;
yield 2;
yield 3;
}
}
let instance = new MyClass();
let iterator = instance.createIterator();
This code creates a class called MyClass
with a createIterator()
generator method. The method returns an iterator whose values are hardcoded into the generator. Generator methods are useful when you have an object that represents a collection of values and you’d like to iterate over those values easily. Arrays, sets, and maps all have multiple generator methods to account for the different ways developers need to interact with their items.
While generator methods are useful, defining a default iterator for your class is much more helpful if the class represents a collection of values. You can define the default iterator for a class by using Symbol.iterator
to define a generator method, such as:
class Collection {
constructor() {
this.items = [];
}
*[Symbol.iterator]() {
yield *this.items.values();
}
}
var collection = new Collection();
collection.items.push(1);
collection.items.push(2);
collection.items.push(3);
for (let x of collection) {
console.log(x);
}
// Output:
// 1
// 2
// 3
This example uses a computed name for a generator method that delegates to the values()
iterator of the this.items
array. Any class that manages a collection of values should include a default iterator because some collection-specific operations require collections they operate on to have an iterator. Now, any instance of Collection
can be used directly in a for-of
loop or with the spread operator.
Adding methods and accessor properties to a class prototype is useful when you want those to show up on object instances. If, on the other hand, you’d like methods or accessor properties on the class itself, then you’ll need to use static members.