views:

874

answers:

2

Summary

Can you explain the reasoning behind the syntax for encapsulated anonymous functions in JavaScript? Why does this work: (function(){})(); but this doesn't: function(){}();?


What I know

In JavaScript, one creates a named function like this:

function twoPlusTwo(){
    alert(2 + 2);
}
twoPlusTwo();

You can also create an anonymous function and assign it to a variable:

var twoPlusTwo = function(){
    alert(2 + 2);
};
twoPlusTwo();

You can encapsulate a block of code by creating an anonymous function, then wrapping it in brackets and executing it immediately:

(function(){
    alert(2 + 2);
})();

This is useful when creating modularised scripts, to avoid cluttering up the current scope, or global scope, with potentially conflicting variables - as in the case of Greasemonkey scripts, jQuery plugins, etc.

Now, I understand why this works. The brackets enclose the contents and expose only the outcome (I'm sure there's a better way to describe that), such as with (2 + 2) === 4.


What I don't understand

But I don't understand why this does not work equally as well:

function(){
    alert(2 + 2);
}();

Can you explain that to me?

+23  A: 

It doesn't work because it is being parsed as a FunctionDeclaration, and the name identifier of function declarations is a mandatory.

When you surround it with parentheses it is evaluated as a FunctionExpression, and function expressions can be named or not.

The grammar of a FunctionDeclaration looks like this:

FunctionDeclaration :
function Identifier ( FormalParameterListopt ) {FunctionBody}

And the one of FunctionExpressions:

    FunctionExpression :
    function Identifieropt (FormalParameterListopt) {FunctionBody}

As you can see the Identifier token in FunctionExpressions is optional, therefore we can have a function expression without a name defined:

(function () {
    alert(2 + 2);
}());

Or named function expression:

(function foo() {
    alert(2 + 2);
}());

The Parentheses (formally called the Grouping Operator) can surround only expressions, and a function expression is evaluated.

The two grammar productions can be ambiguous, and they can look exactly the same, for example:

function foo () {} // FunctionDeclaration

0,function foo () {} // FunctionExpression

The parser knows if it's a FunctionDeclaration or a FunctionExpression, depending on the context where it appears.

In the above example, the second one is an expression because the Comma operator can also handle only expressions.

On the other hand, FunctionDeclaration's could actually appear only in what's called "Program" code, meaning code outside in the global scope, and inside the FunctionBody of other functions.

Functions inside blocks should be avoided, because they can lead an unpredictable behavior, e.g.:

if (true) {
  function foo () { alert('true'); }
} else {
  function foo () { alert('false!'); }
}

foo(); // true? false? why?

The above code should actually produce a SyntaxError, since a Block such those can only contain statements (and the ECMAScript Specification doesn't define any function statement), but most implementations are tolerant, and will simply take the second function, the one which alerts 'false!'.

The Mozilla implementations -Rhino, SpiderMonkey,- have a different behavior. Their grammar contains a non-standard Function Statement, meaning that the function will be evaluated at run-time, not at parse time, as it happens with FunctionDeclarations. In those implementations we will get the first function defined.


Functions can be declared in different ways, compare the following:

1- A function defined with the Function constructor assigned to the variable multiply:

  var multiply = new Function("x", "y", "return x * y;");

2- A function declaration of a function named multiply:

  function multiply(x, y) {
     return x * y;
  }

3- A function expression assigned to the variable multiply:

  var multiply = function (x, y) {
     return x * y;
  };

4- A named function expression *func_name*, assigned to the variable multiply:

  var multiply = function func_name(x, y) {
     return x * y;
  };
CMS
I think the term is function declaration rather than function statement.
Tim Down
This is a great answer. It does seem to be linked intimately with how the source text is parsed- and the structure of the BNF. in your example 3, should I say that it is a function expression because it follows an equals sign, wheras that form is a function declaration/statement when it appears on a line by itself? I wonder what the purpose of that would be- is it just interpreted as a named function declaration, but without a name? What purpose does that serve if you're not assigning it to a variable, naming it, or calling it?
Breton
Aha. Very useful. Thanks, CMS. This part of the Mozilla docs that you linked to is especially enlightening: https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Functions_and_function_scope#Function_constructor_vs._function_declaration_vs._function_expression
Premasagar
+1, although you had the closing bracket in the wrong position in the function expression :-)
NickFitz
@NickFitz: Both: `(function(){})();` and `(function(){}());` are valid...
CMS
a year old... and still liking it
vol7ron
+3  A: 

CMS's answer is correct. For an excellent in-depth explanation of function declarations and expressions, see this article by kangax.

Tim Down
Great stuff. Thanks for the link, Tim.
Premasagar