ES6 Everyday: Generator Functions

Remember yesterday when I showed you how to write a function that would generate an iterator?

function getIterator()
{
  var values = ['Alligator', 'Bear', 'Lion'];
  var currIndex = 0;
  
  return {
    
    next: function() {
      
      return currIndex >= values.length
        ? { done: true }
      	: { done: false, value: values[currIndex++] };
      
    }
    
  };
}

var myIterator = getIterator();
console.log(myIterator.next().value); // Alligator
console.log(myIterator.next().value); // Bear
console.log(myIterator.next().value); // Lion
console.log(myIterator.next().done); // true

Cool and all, but phew, that’s a lot to write.

Luckily, ES6 provides an easier way to write these functions that generate iterators. Actually, they are called generator functions and you define them using function*:

function* myGeneratorFunction()
{
}

Within our generator function, we can use the yield keyword to sequentially return values:

function* getIterator()
{
  yield "Alligator";
  yield "Bear";
  yield "Lion";
}

var iterator = getIterator();
console.log(iterator.next().value); // Alligator
console.log(iterator.next().value); // Bear
console.log(iterator.next().value); // Lion
console.log(iterator.next().done); // true

These generator functions return a Generator object, an object that adheres to both the iterable and iterator protocols.

So, of course, we can use them in a for..of loop:

function* getMenu()
{
  yield "Steak";
  yield "Mashed Potatoes";
  yield "Porter";
}

for(let item of getMenu())
{
  console.log(item); // Steak, Mashed Potatoes, Porter
}

And, if you’re wondering, yes, you can have anonymous generator functions too:

var getPalette = function*()
{
  yield "Blue";
  yield "Red";
  yield "Orange";
}