javascriptcoding-stylefunction-expressionjavascript-function-declaration

Which is preferred: inline function expressions or stand-alone function declarations?


Can any body throw me some arguments for using inline functions against passing predefined function name to some handler.

I.e. which is better:

(function() {
  setTimeout(function() { /*some code here*/ }, 5);
})();

versus

(function() {
  function invokeMe() {
    /*code*/
  }
  setTimeout(invokeMe, 5);
})();

Strange question, but we are almost fighting in the team about this.


Solution

  • Named functions

    There is some serious misuse of terminology in the question and answers on this page. There is nothing about whether or not a function is inline (a function expression) that says you cannot name it.

    This is using a function expression:

    setTimeout(function doSomethingLater() { alert('In a named function.'); }, 5);
    

    and this is using a function statement:

    function doSomethingLater() { alert('In a named function.'); }
    setTimeout(doSomethingLater, 5);
    

    Both examples are using named functions and both get the same benefits when it comes to debugging and profiling tools!

    If the name is specified (the text after "function" but before the parenthesis) then it is a named function regardless of whether it is inline or declared separately. If the name is not specified then it is "anonymous".

    Note: T.J. points out that IE mishandles named function expressions in a non-trivial way (See: http://kangax.github.com/nfe/#jscript-bugs) and this is important to note, I'm simply trying to make a point about the terminology.

    Which should you use?

    In response to your direct question, you should use a named function statement if the function could ever be used from any other place in your code. If the function is being used in exactly one place and has no relevance anywhere else then I would use a function expression unless it is prohibitively long or otherwise feels out of place (for style reasons). If you use an inline function expression then it is often useful to name it anyway for the purposes of debugging or code clarity.

    Memory leaks

    Whether you name your function, use a function statement, or use a function expression has little impact on the memory leak issue. Let me try to explain what causes these leaks. Take a look at this code:

    (function outerFunction() {
        var A = 'some variable';
    
       doStuff();
    })();
    

    In the code above, when "outerFunction" finishes "A" goes out of scope and can be garbage collected, freeing that memory.

    What if we add a function in there?

    (function outerFunction() {
        var A = 'some variable';
    
       setTimeout(function(){ alert('I have access to A whether I use it or not'); }, 5);
    })();
    

    In this code (above) the function expression we are passing to setTimeout has a reference to "A" (through the magic of closure) and even after "outerFunction" finishes "A" will remain in memory until the timeout is triggered and the function is dereferenced.

    What if we pass that function to something other than setTimeout?

    (function outerFunction() {
        var A = 'some variable';
    
       doStuff(function(){ alert('I have access to A whether I use it or not'); });
    })();
    
    function doStuff(fn) {
        someElement.onclick = fn;
    }
    

    Now the function expression we are passing to "doStuff" has access to "A" and even after "outerFunction" finishes "A" will remain in memory for as long as there is a reference to the function we passed into doStuff. In this case, we are creating a reference to that function (as an event handler) and therefore "A" will remain in memory until that event handler is cleared. (e.g. someone calls someElement.onclick = null)

    Now look at what happens when we use a function statement:

    (function outerFunction() {
        var A = 'some variable';
    
        function myFunction() { alert('I have also have access to A'); };
        doStuff(myFunction);
    })();
    

    The same problem! "myFunction" will be cleaned up only if "doStuff" does not hold a reference to it and "A" will only be cleaned up when "myFunction" is cleaned up. It does not matter whether we used a statement or an expression; what matters is if a reference to that function is created in "doStuff"!