Can you explain the reasoning behind the syntax for encapsulated anonymous functions in JavaScript? Why does this work: (function(){})();
but
Those extra parenthesis creates extra anonymous functions between global namespace and anonymous function that contains the code. And in Javascript functions declared inside other functions can only access namespace of parent function that contains them. As there is extra object (anonymious function) between global scope and actual code scoping is not retained.
Perhaps the shorter answer would be that
function() { alert( 2 + 2 ); }
is a function literal that defines an (anonymous) function. An additional ()-pair, which is interpreted as an expression, is not expected at toplevel, only literals.
(function() { alert( 2 + 2 ); })();
is in an expression statement that invokes an anonymous function.
(function(){
alert(2 + 2);
})();
Above is valid syntax because anything passed inside parenthesis is consider as function expression.
function(){
alert(2 + 2);
}();
Above is not valid syntax. Because java script syntax parser looks for function name after function keyword since it doesn't find anything it throws an error.
You can also use it like:
! function() { console.log('yeah') }()
or
!! function() { console.log('yeah') }()
!
- negation op converts the fn definition to fn expression, therefore, you can invoke it immediately with ()
. Same as using 0,fn def
or void fn def
I have just another small remark. Your code will work with a small change:
var x = function(){
alert(2 + 2);
}();
I use the above syntax instead of the more widely spread version:
var module = (function(){
alert(2 + 2);
})();
because I didn't manage to get the indentation to work correctly for javascript files in vim. It seems that vim doesn't like the curly braces inside open parenthesis.
It doesn't work because it is being parsed as a FunctionDeclaration
, and the name identifier of function declarations is 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:
function Identifier ( FormalParameterListopt ) { FunctionBody }
And FunctionExpression
s:
function Identifieropt ( FormalParameterListopt ) { FunctionBody }
As you can see the Identifier
(Identifieropt) token in FunctionExpression
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 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 FunctionDeclaration
s. 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;
};