When looking for examples of generator function definitions, one of the foremost that you will find is one for generating the fibonacci sequence. One of the great things about the upcoming version of JavaScript is the fact that it will allow generator functions to be defined. The following is the JavaScript 1.7 code, from the Mozilla Developer Network, that could be used to write a fibonacci generator function:

function fib() {
  var temp, num1 = 0, num2 = 1;
  while (1) {
    yield num1;
    temp = num1;
    num1 = num2;
    num2 += temp;
  }
}

// fibonacci generator function
var genFib = fib();

// Print the first ten numbers in the fibonacci sequence.
for (var arr = [], i = 0; i < 10; i++) {
  arr.push(genFib.next());
}
alert("1st 10 fibonacci sequence numbers:\n" + arr.join("\n"));

If you are familiar with Python, you will notice that the code is quite similar. Unfortunately, generator functions are not available in most browsers at the moment. The question is then, can we still design a fibonacci function which can be called iteratively to retrieve the next value in the sequence without store the previous values in the global scope? Of course we can! We can simply use a closure in order to create variables that are only accessible to the function created within the closure. Here is an equivalent function that will work in all browsers:

function fib() {
  return {
    next : (function() {
      var temp, num1 = 0, num2 = 1;
      return function() {
        temp = num1;
        num1 = num2;
        num2 += temp;
        return temp;
      };
    })()
  };
}

// fibonacci generator function
var genFib = fib();

// Print the first ten numbers in the fibonacci sequence.
for (var arr = [], i = 0; i < 10; i++) {
  arr.push(genFib.next());
}
alert("1st 10 fibonacci sequence numbers:\n" + arr.join("\n"));

It is true that this implementation is not as good as having a real generator function, but it does prove that having the power of closures at your disposal can come in handy. 😀

Another example on the MDN uses the send() function defined for generator functions to change the internal state of a generator. Here is an example of defining the fibonacci function and then using the send() function:

function fib() {
  var temp, num1 = 0, num2 = 1;
  while (1) {
    var reset = yield num1;
    if(reset) {
      num1 = 1;
      num2 = 0;
    }
    temp = num1;
    num1 = num2;
    num2 += temp;
  }
}

var genFib = fib();
alert(genFib.next());     // 0
alert(genFib.next());     // 1
alert(genFib.next());     // 1
alert(genFib.next());     // 2
alert(genFib.next());     // 3
alert(genFib.next());     // 5
alert(genFib.next());     // 8
alert(genFib.send(true)); // 0
alert(genFib.next());     // 1
alert(genFib.next());     // 1

The question is, how can we accomplish this same thing with the closure method? Here one way:

function fib() {
  var temp, reset, num1 = 0, num2 = 1;
  function getNext(reset) {
    if(reset) {
      temp = num1 = 0;
      num2 = 1;
    }
    temp = num1;
    num1 = num2;
    num2 += temp;
    return temp;
  }
  return {
    next : function() { return getNext(); },
    send : getNext
  };
}

var genFib = fib();
alert(genFib.next());     // 0
alert(genFib.next());     // 1
alert(genFib.next());     // 1
alert(genFib.next());     // 2
alert(genFib.next());     // 3
alert(genFib.next());     // 5
alert(genFib.next());     // 8
alert(genFib.send(true)); // 0
alert(genFib.next());     // 1
alert(genFib.next());     // 1

As you can see, I had to change the way that next() is defined in order to make send() simulate what is available for the generator function. Once again, this approach does work on all browsers, but it would be better as a generator function. 😉


Leave a Reply

Your email address will not be published. Required fields are marked *