OdeToCode IC Logo

Generators in ECMAScript 6

Monday, February 16, 2015

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.