JS Tip of the Day: Generators for Iterables

Generators for Iterables
Version: ES2015
Level: Intermediate

Generator functions are functions that make generator objects. Generator objects are iterables which means they can be iterated over using a for...of loop or spread using spread syntax (...) in arrays and function call argument lists. The values iterated over for a generator object are those yielded by it’s generator function. If you ever need an iterable with the output of a dynamic set of values, using a generator might be the way to go.

To make a generator function, you would use the normal function declaration syntax but follow the function keyword with an asterisk *. Any value preceded by the yield operator within that function becomes a value provided to the iteration of the generator object it creates when called.

function * makeGenerator () {
    yield 1;
    yield 2;
    yield 3;
}

let myGenerator = makeGenerator();
console.log([...myGenerator]); // [1, 2, 3]

While arrays are iterable, normal JavaScript objects are not. We can use a generator function to allow us to iterate over an object’s values with a for…of loop.

function * valuesIn (obj) {
    for (let key in obj) {
        yield obj[key];
    }
}

let pets = { cat: 'Purrseus', dog: 'Barkansas' };
for (let name of valuesIn(pets)) {
    console.log(name);
}
/* logs:
Purrseus
Barkansas
*/

If you’re familiar with the builtin Object.values(), this behaves much in the same way except that Object.values() creates an array first. Then when you iterate over the values, you iterate through that array. With valuesIn above, you’re not creating the intermediary array first. When you iterate over the values of a valuesIn generator, you are stepping through the for...in loop directly.

valuesIn is just a simple example, but you can imagine doing a lot more in generator functions. They can be a powerful tool for managing iteration or creating iterable objects. Future tips will explore their use further.

More info: