Explain the encapsulated anonymous function syntax
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;
};
Great answers have already being posted. But I want to note that function declarations return an empty completion record:
14.1.20 - Runtime Semantics: Evaluation
FunctionDeclaration :
function
BindingIdentifier(
FormalParameters)
{
FunctionBody}
- Return NormalCompletion(empty).
This fact is not easy to observe, because most ways of attempting to get the returned value will convert the function declaration to a function expression. However, eval
shows it:
var r = eval("function f(){}");
console.log(r); // undefined
Calling an empty completion record makes no sense. That's why function f(){}()
can't work. In fact the JS engine does not even attempt to call it, the parentheses are considered part of another statement.
But if you wrap the function in parentheses, it becomes a function expression:
var r = eval("(function f(){})");
console.log(r); // function f(){}
Function expressions return a function object. And therefore you can call it: (function f(){})()
.
In javascript, this is called Immediately-Invoked Function Expression (IIFE) .
In order to make it a function expression you've to:
enclose it using ()
place a void operator before it
assign it to a variable.
Otherwise it will be treated as function definition and then you won't be able to call/invoke it at the same time by the following way:
function (arg1) { console.log(arg1) }();
The above will give you error. Because you can only invoke a function expression immediately.
This can be achieved couple of ways: Way 1:
(function(arg1, arg2){
//some code
})(var1, var2);
Way 2:
(function(arg1, arg2){
//some code
}(var1, var2));
Way 3:
void function(arg1, arg2){
//some code
}(var1, var2);
way 4:
var ll = function (arg1, arg2) {
console.log(arg1, arg2);
}(var1, var2);
All above will immediately invoke the function expression.
Even though this is an old question and answer, it discusses a topic that to this day throws many developers for a loop. I can't count the number of JavaScript developer candidates I've interviewed who couldn't tell me the difference between a function declaration and a function expression and who had no clue what an immediately invoked function expression is.
I'd like to mention, though, one very important thing which is that Premasagar's code snippet wouldn't work even if he had given it a name identifier.
function someName() {
alert(2 + 2);
}();
The reason this wouldn't work is that the JavaScript engine interprets this as a function declaration followed by a completely unrelated grouping operator that contains no expression, and grouping operators must contain an expression. According to JavaScript, the above snippet of code is equivalent to the following one.
function someName() {
alert(2 + 2);
}
();
Another thing I'd like to point out that may be of some use to some people is that any name identifier you provide for a function expression is pretty much useless in the context of the code except from within the function definition itself.
var a = function b() {
// do something
};
a(); // works
b(); // doesn't work
var c = function d() {
window.setTimeout(d, 1000); // works
};
Of course, using name identifiers with your function definitions is always helpful when it comes to debugging code, but that's something else entirely... :-)