Coded-Aesthetics

ES6 generators, iterators and the yield statement

Think of generator functions as functions being able to have a lot of consecutive return values that can be iterated over.

Generator functions are declared by adding the * (asterisk) sign after the function statement:

function* gen() { /* do things here */ };

They “return” values through the yield statement. Here is an example:

function* gen() {
  yield 1;
  yield 4;
  yield 9;
}

You can harvest these values by using the iterator returned by the generator function and calling its next() method:

let it = gen();
it.next(); /* returns {value: 1, done: false} */
it.next(); /* returns {value: 4, done: false} */
it.next(); /* returns {value: 9, done: false} */
it.next(); /* returns {value: undefined, done: true} */

So what yield really does is define iteration steps that are returned when the next() function is called. Actually the execution of the generator function is halted until the next value is requested.
So it’s entirely possible to have an endless loop in you generator:

function* gen() {
  let i = 0;
  while (1) {
     yield i++;
  }
}

You can iterate over the values with a for loop:

for (let cur = it.next(); !cur.done; cur = it.next()) {
  console.log(cur.value);
}

or a do while loop:

do {
  var cur = it.next();
  console.log(cur.value);
} while (!cur.done)

But the nicest way is using the for … of method:

for (let value of it) {
  console.log(value);
}

These will all output

1
4
9

Generators and arrays

Arrays are already iteratables so you can choose to yield the whole array or its individual entries.

  function* gen1() { yield ["a", "b", "c"]; }
  function* gen2() { yield* ["a", "b", "c"]; }

Note the subtle difference: in gen2() the array’s entries are yielded using yield*

  let it1 = gen1();
  for (let value of it1) {
    console.log(value);
  }
  /* will output 
     ["a", "b", "c"] 
  */
  let it2 = gen2();
  for (let value of it1) {
      console.log(value);
  }
  /* will output 
     "a" 
     "b"
     "c"
  */
  

Here are some examples of generator functions:

Prime number generator

function* prime() {
    var cur = 3; /** start with 3 **/
    yield 2; /** 2 is a prime **/
    let foundPrimes = [2]; /** store in array of found primes **/
    while(1) {
      let isPrime = true;
      /** loop through found primes **/
      for (var i = 0; i < foundPrimes.length; i++) {
        let p = foundPrimes[i];
        /** if the current value is divisible by one 
        of the found primes it is not prime itself **/
        if (cur % p === 0) {
          isPrime = false;
          break;
        }
        /** we need not go further than cur/2 **/
        if (p > cur/2) {
          break;
        }
      }
      /** if a prime was found yield it 
      and add it to the array of found primes **/
      if (isPrime) {
        yield cur;
        foundPrimes.push(cur);
      }
      ++cur;
    }
}
JsFiddle

Fibonacci numbers generator

/* generates 'count' fibonacci number pairs */
function* fib(count) {
   let a = 1;
   let b = 1;
   for (var i = count; i--;) {
     yield a;
     yield b;
     a = a+b;
     b = a+b;
   }
}
JsFiddle

the first ten fibonacci numbers can be generated like so:

let it = fib(5);
for (let value of it) {
  console.log(value);
}

/** will output:
1
1
2
3
5
8
13
21
34
55
**/