You’ll know you are looking at a generator, or more properly, a generator function, because a generator function contains an asterisk in the declaration.
function*() { }
Once you have a generator function, you can use the yield keyword inside to return multiple values to the caller.
let numbers = function*() { yield 1; yield 2; yield 3; };
But, the numbers don’t come back to the caller all at once. Internally, the runtime builds an iterator for you, so a caller can iterate through the results one by one. You can write a low level iterator and call next to move through each value, or use a for of loop.
let sum = 0; for(let n of numbers()) { sum += n; } expect(sum).toBe(6);
Going back to the classroom class we used in the last ES6 post, we can now make a classroom an iterable simply using yield.
class Classroom { constructor(...students) { this.students = students; } *[Symbol.iterator]() { for(let s of this.students) yield s; } } var scienceClass = new Classroom("Tim", "Sue", "Joy"); var students = []; for(let student of scienceClass){ students.push(student); } expect(students).toEqual(["Tim", "Sue", "Joy"])
Notice how the iterator method needs an asterisk before the opening square bracket. The syntax is quirky, but an asterisk is always required when defining a generator function, because generator functions need to behave differently than normal functions right from the start. That’s the topic for the next post in this series.