<alt>descriptive text goes here</alt>

Closure vs Rewrite

At The Rich Web Experience 2008, Douglas Crockford gave an example of a function which would take an integer and return the word for that number by retrieving the word from an array. He started by having the array created globally and the function would access it. This is bad because the array is global. He then created the array each time the function was called. This is also bad because you are creating the array repeatedly. Finally, he did it with a closure, creating the array in a self executing function on page load and returning an inner function which can access the array. It was similar to this, minus the alert and validation:

var showNumber_Closure=function(){
  alert('This is called on page init');
  var n=['Zero','One','Two','Three','Four','Five','Six','Seven','Eight','Nine'];
  return function(i){
    if(!(i in n))return 'Invalid Number';
    return n[i];
  }
}();

This is fine and works well. The problem I have with it is it executes on page load, but it may never even be used. If you have a lot of functions following this pattern and you only may use a few of them, thats a lot of wasted cycles.

I proposed an alternative to him which looked like this, again, minus the alert and validation:

var showNumber_Rewrite=function(i){
  alert('This is called when it is needed, but only once');
  var n=['Zero','One','Two','Three','Four','Five','Six','Seven','Eight','Nine'];
  showNumber_Rewrite=function(i){
    if(!(i in n))return 'Invalid Number';
    return n[i];
  };
  return showNumber_Rewrite(i);
}

The difference is this does not execute at all until it is actually needed. The first time it is called, the array is created and the function itself is rewritten, creating a closure, such that each subsequent call just validates and returns the string. Unlike his example, if you never need it, it never executes.

He didn’t like it. He couldn’t give me a real reason. I also showed it to another JS presenter who liked it until I said Crockford didn’t.

You can test it by running this:

alert(showNumber_Rewrite(-3)); //Invalid Number
alert(showNumber_Rewrite(3)); //Three

alert(showNumber_Closure(5)); //Five
alert(showNumber_Closure(74)); //Invalid Number
Posted in JavaScript

3 Responses to “Closure vs Rewrite”

  1. On January 11th, 2009 at 11:13 am, Timo Reitz said:

    Try this code directly after the definition of showNumber_Rewrite, it will run the initialization several times (if used directly after the definition of showNumber_Rewrite):

    function forEach(a, f){
        var result=[];
        for (var i=0,l=a.length;i<l;i++){
            result.push(f(a[i]));
        }
        return result;
    }
    var numbers=forEach([0,1,2,3,4,5,6,7,8,9],showNumber_Rewrite);
    

    Worse, before the rewriting of showNumber_Rewrite, references to it could be hold by other pieces of code. This could lead to the initialisation called over and over again, which would be inefficient and (in cases of side-effects of the initialisation) error-prone.

    I tried something similar, when I experimented with functions decorating prototype objects with methods which replaced themselves the first time any of them was run with methods specific to the object itself. I dismissed this pattern because I became aware someone could take the reference of the method before it was called one, thus possibly screwing up things (when calling this method multiple times).

    It is possible to create a method which tests if an initialization has occurred, but it will be a bit less efficient than a direct method, because it would test it on every call.

    I think it’s the old “beautiful vs. efficient” here.

    Yours sincerely,
    Timo Reitz

  2. On January 26th, 2009 at 10:47 pm, Anonymous said:

    Your pattern saves one if statement per invocation. I don’t think that is a sufficient payoff to justify the trick.

    var showNumber = function (i) {
        var n;
        return function (i) {
            if (!n) {
                n = ['Zero','One','Two','Three','Four',
                     'Five','Six','Seven','Eight','Nine'];
            }
            return n[i] || 'Invalid Number';
        };
    }();
    
  3. On January 31st, 2009 at 11:48 pm, Alan said:

    @Timo: The same issue also arises if you try to use this pattern for an event handler. Any time you assign the function to something before it has been run once the init will run on each call. I still feel in a controlled environment it is beneficial.

    @Anonymous: I think you missed the point of the post which was to have the function NOT run until it is needed. Your example runs once when the page is loaded which is what I am trying to avoid. In fact, your example is even less efficient than my showNumber_Closure since you added an unnecessary if statement. The point is, don’t do the extra operations if you don’t need to.

Leave a Comment