Sunday, May 27, 2012

JavaScript: var functionName = function() {} vs function functionName() {}


I've recently started maintaining someone else's JavaScript code. I'm fixing bugs, adding features and also trying to tidy up the code and make it more consistent.



The previous developer uses two ways of declaring functions and I can't work out if there is a reason behind it or not.



The two ways are:




var functionOne = function() {
// Some code
}




function functionTwo() {
// Some code
}



What are the reasons for using these two different methods and what are the pros and cons of each? Is there anything that can be done with one method that can't be done with the other?


Source: Tips4all

10 comments:

  1. The difference is that functionTwo is defined at parse-time for a script block, whereas functionOne is defined at run-time. For example:

    <script>

    // Error
    functionOne();

    var functionOne = function()
    {
    }

    </script>



    <script>

    // No error
    functionTwo();

    function functionTwo()
    {
    }

    </script>

    ReplyDelete
  2. First I want to correct RoBorg: function abc(){} is scoped too — the name abc is defined in the scope where this definition is encountered. Example:

    function xyz(){
    function abc(){};
    // abc is defined here...
    }
    // ...but not here


    Secondly, it is possible to combine both styles:

    var xyz = function abc(){};


    xyz is going to be defined as usual, abc is undefined in all browsers but IE — do not rely on it being defined. But it will be defined inside its body:

    var xyz = function abc(){
    // xyz is visible here
    // abc is visible here
    }
    // xyz is visible here
    // abc is undefined here


    If you want to alias functions on all browsers use this kind of declaration:

    function abc(){};
    var xyz = abc;


    In this case both xyz and abc are aliases of the same object:

    console.log(xyz === abc); // prints "true"


    One compelling reason to use the combined style is the "name" attribute of function objects (not supported by IE). Basically when you define a function like this:

    function abc(){};
    console.log(abc.name); // prints "abc"


    its name is automatically assigned. But when you define it like this:

    var abc = function(){};
    console.log(abc.name); // prints ""


    its name is empty — we created an anonymous function and assigned it to some variable.

    Another good reason to use the combined style is to use a short internal name to refer to itself, while providing a long non-conflicting name for external users:

    // assume really.long.external.scoped is {}
    really.long.external.scoped.name = function shortcut(n){
    // let's call itself recursively:
    shortcut(n - 1);
    // ...
    // let's pass itself as a callback:
    someFunction(shortcut);
    // ...
    }


    In the example above we can do the same with an external name, but it'll be too unwieldy (and slower).

    (Another way to refer to itself is to use arguments.callee, which is still relatively long, and not supported in the strict mode.)

    Deep down JavaScript treats both statements differently. This is a function declaration:

    function abc(){}


    abc here is defined everywhere in the current scope:

    // we can call it here
    abc(); // works
    // yet it is defined down there
    function abc(){}
    // we can call it again
    abc(); // works


    This is a function expression:

    var xyz = function(){};


    xyz here is defined from the point of assignment:

    // we can't call it here
    xyz(); // UNDEFINED!!!
    // now it is defined
    xyz = function(){}
    // we can call it here
    xyz(); // works


    Function declaration vs. function expression is the real reason why there is a difference demonstrated by RoBorg.

    Fun fact:

    var xyz = function abc(){};
    console.log(xyz.name); // prints "abc"


    Personally I prefer the "function expression" declaration because this way I can control the visibility. When I define the function like that:

    var abc = function(){};


    I know that I defined the function locally. When I define the function like that:

    abc = function(){};


    I know that I defined it globally providing that I didn't define abc anywhere in the chain of scopes. This style of definition is resilient even when used inside eval(). While this definition:

    function abc(){};


    depends on the context and may leave you guessing where it is actually defined, especially in the case of eval() — the answer is: it depends on browser.

    ReplyDelete
  3. Speaking about the global context, both, the var statement and a FunctionDeclaration at the end will create a non-deleteable property on the global object, but the value of both can be overwritten.

    The subtle difference between the two ways is that when the Variable Instantiation process runs (before the actual code execution) all identifiers declared with var will be initialized with undefined, and the ones used by the FunctionDeclaration's will be available since that moment, for example:

    alert(typeof foo); // 'function', it's already available
    alert(typeof bar); // 'undefined'
    function foo () {}
    var bar = function () {};
    alert(typeof bar); // 'function'


    The assignment of the bar FunctionExpression takes place until runtime.

    A global property created by a FunctionDeclaration can be overwritten without any problems just like a variable value, e.g.:

    function test () {}
    test = null;


    Another obvious difference between your two examples is that the first function doesn't have a name, but the second has it, which can be really useful when debugging (i.e. inspecting a call stack).

    About your edited first example (foo = function() { alert('hello!'); };), it is an undeclared assignment, I would highly encourage you to always use the var keyword.

    With an assignment, without the var statement, if the referenced identifier is not found in the scope chain, it will become a deleteable property of the global object.

    Also, undeclared assignments throw a ReferenceError on ECMAScript 5 under Strict Mode.

    A must read:


    Named function expressions demystified


    Note: This answer has been merged from another question, in which the major doubt and misconception from the OP was that identifiers declared with a FunctionDeclaration, couldn't be overwritten which is not the case.

    ReplyDelete
  4. The two code snippets you've posted there will, for almost all purposes, behave the same way.

    However, the difference in behaviour is that with the first variant, that function can only be called after that point in the code.

    With the second variant, the function is available to code that runs above where the function is declared.

    This is because with the first variant, the function is assigned to the variable foo at run time. In the second, the function is assigned to that identifier foo at parse time.

    More technical info

    Javascript has three ways of defining functions.


    Your first snippet shows a function expression. This involves using the "function" operator to create a function - the result of that operator can be stored in any variable or object property. The function expression is powerful that way. The function expression is often called an "anonymous function" because it does not have to have a name,
    Your second example is a function declaration. This uses the "function" statement to create a function. The function is made available at parse time and can be called anywhere in that scope. You can still store it in a variable or object property later.
    The third way of defining a function is the "Function()" constructor, which is not shown in your original post. It's not recommended to use this as it works the same way as eval(), which has its problems.

    ReplyDelete
  5. Other commenters have already covered the semantic difference of the two variants above. I wanted to note a stylistic difference: Only the "assignment" variation can set a property of another object.

    I often build javascript modules with a pattern like this:

    (function(){
    var exports = {};

    function privateUtil() {
    ...
    }

    exports.publicUtil = function() {
    ...
    };

    return exports;
    })();


    With this pattern, your public functions will all use assignment, while your private functions use declaration.

    (Note also that assignment should require a semicolon after the statement, while declaration prohibits it.)

    ReplyDelete
  6. An important reason is to add one and only one variable as the "Root" of your namespace...

    var MyNamespace = {}
    MyNamespace.foo= function() {
    }


    or

    var MyNamespace {
    foo: function() {
    },
    ...
    }


    There are many techniques for namespacing. Its become more important with the plethora of JavaScript modules available.

    Also see http://stackoverflow.com/questions/881515/javascript-namespace-declaration

    ReplyDelete
  7. In terms of code maintenance cost named functions are more preferable:


    independent from place where they are declared( but still limited by scope).
    More resistant to mistakes like conditional initialization.(You are still able to override if wanted to).
    The code becomes more readable by allocating local functions separately of scope functionality. Usually in the scope the functionality goes first, followed by declarations of local functions.
    in debugger you will clearly see on call stack the function name instead of "anonymous/evaluated" function.


    I suspect more PROS for named functions are follow.
    And what is listed as advantage of named functions is disadvantage for anonymous ones.

    Historically anonymous functions appeared from inability of JS as language to list members with named functions:

    { member:function(){/* how to make this.member a named function? */}
    }

    ReplyDelete
  8. This might be the best and concise answer I've ever encountered. @Hemant Metalia point out this link for me to answer my similar question.

    ReplyDelete
  9. In computer science terms, we are talking about anonymous functions and named functions. I think the most important difference is that an anonymous function is not bound to an name, hence the name anonymous function. In Javascript it is a first class object dynamically declared at runtime.

    For more informationen on anonymous functions and lambda calculus, Wikipedia is a good start (http://en.wikipedia.org/wiki/Anonymous_function).

    ReplyDelete
  10. function name() {
    // …
    }


    is syntax sugar, as the JavaScript parser creates a property that attaches to the call object if the function is defined inside another function, and to the global object in the other cases; as it is the parser to do that, I think the term "syntax sugar" is correct.

    ReplyDelete