Function Expressions and Function Statements

The best way to define your functions in JavaScript is exactly the same way as you define any other variables. If you define them the same way then it is completely obvious that they work exactly the same way as for any other JavaScript variable except that in addition they can be run.

Let's consider a simple example.

Here we define an addEvent function that will add event processing to both modern browsers and to older versions of IE such as IE6 through 8. This version has three function declarations all of which are assigned to the same variable.

var addEvent = function(ob, type, fn) {
   if (window.addEventListener)
      addEvent = function(ob, type, fn ) {
         if ('string' === typeof ob) ob = document.getElementById(ob);
         ob.addEventListener(type, fn, false );
         };
   else if (document.attachEvent)
       addEvent = function(ob, type, fn ) {
          var eProp = type + fn;
          if ('string' === typeof ob) ob = document.getElementById(ob);
          ob['e'+eProp] = fn;
          ob[eProp] = function(){ob['e'+eProp]( window.event );};
          ob.attachEvent( 'on'+type, ob[eProp]);
          };
  addEvent(ob, type, fn);
}

In the above variant we simply have three places where we assign a function to a variable directly. In each case the function is assigned to the same variable so each time the function is run only one of the three functions gets run. Well that's not quite true since the first time the function is run the function overwrites itself and then calls itself again to run the replacement. All of this is obvious from the code.

Now compare it to the following version that uses function statements to define two of the functions.

var addEvent = (function () {
    function eventListenerFunc(ob, type, fn) {
        if ("string" === typeof ob) ob = document.getElementById(ob);
        ob.addEventListener(type, fn, false);
    }
    function attachEventFunc(ob, type, fn) {
        var eProp = type + fn;
        if ("string" === typeof ob) ob = document.getElementById(ob);
        ob["e" + eProp] = fn;
        ob[eProp] = function () { ob["e" + eProp](window.event);};
        ob.attachEvent("on" + type, ob[eProp]);
    }
    if (window.addEventListener) {
        return eventListenerFunc;
    } else if (document.attachEvent) {
        return attachEventFunc;
    }
}());

This variant is more convoluted and actually has just as many functions being assigned to variables as the earlier version, it just isn't as obvious.

The only difference between these two versions other than for the first being more readable is that the second gives the second and third functions names so that those functions can be assigned by name to a variable instead of being assigned directly.

Both of the above versions assign three different functions to the variable addEvent. The only difference is that the first version does it directly whereas the second names the functions before assigning them.

It just makes no sense to use function statements just so you can assign them to variables anyway and since there will always be times when you need to assign functions to variables you may as well define them all that way in the first place instead of declaring the functions using statements first and then assigning them by name.

One more version - combining the IIFE from the second version with the first version so as to get rid of the function statements:

var addEvent = function() {
   if (window.addEventListener)
      return function(ob, type, fn ) {
         if ('string' === typeof ob) ob = document.getElementById(ob);
         ob.addEventListener(type, fn, false );
         };
   else if (document.attachEvent)
       return function(ob, type, fn ) {
          var eProp = type + fn;
          if ('string' === typeof ob) ob = document.getElementById(ob);
          ob['e'+eProp] = fn;
          ob[eProp] = function(){ob['e'+eProp]( window.event );};
          ob.attachEvent( 'on'+type, ob[eProp]);
          };
}();

Provided you notice that we are running the outer function to return one of the inner two functions to assign to addEvent this is perhaps the shortest way to write it but is perhaps not quite as obvious what is happening as with the first version as it is essential that you notice the () at the end (and I missed that when I first saw the second variant of this code).

 

This article written by Stephen Chapman, Felgall Pty Ltd.

go to top

FaceBook Follow
Twitter Follow
Donate