1

I just read Ben Alman's article on Immediately-Invoked Function Expressions and wondered about this part, where he's introducing function expressions and closures (not really related to IIFEs yet):

// ...doesn't it stand to reason that the function expression itself can
// be invoked, just by putting () after it?

function(){ /* code goes here */ }();

// This works! Well, almost. A minor JavaScript syntax issue actually
// requires that ambiguity between function declarations and function
// expressions be eliminated, which can be done by wrapping the function
// expression in parens.

// The following pattern is used universally to create an anonymous
// closure with "privacy":

(function(){ /* code goes here */ })();

// This parens syntax is also valid (I prefer the previous version):

(function(){ /* code goes here */ }());

That last part struck me. Can anybody explain why there are two different syntactical versions for invoking function expressions?

Was this syntax consciously introduced just for invoking anonymous closures? Or is it a by-product of some other syntactical property?

Why does the second version work anyway? The first one makes sense to me from a parser standpoint. The first pair of parens evaluates to a function object, the second pair invokes this function object. But the second one? It doesn't look like it's resolving the mentioned syntactical ambiguity.

Can anybody tell me what I'm missing here?

Henrik Heimbuerger
  • 9,924
  • 6
  • 56
  • 69

2 Answers2

3

All of it happens because JavaScript has two parsing contexts : expression and statement. Writing function foo() {} at statement level defines function foo in that scope, whereas function foo() {} at expression level evaluates to a new anonymous function (that can call itself recursively as foo).

So, whenever that construct is encountered, the parser must determine whether it is at expression or statement level. By default, it assumes to be at statement level, unless convinced otherwise. The brackets are a syntactic way of saying "this is an expression".

So, writing (function() {}) causes the parser to treat the function as an expression. Since expressions can only contain other expressions (no statements), it also follows that if you write (something-that-contains function(){} and-other-stuff) then the function in there will still be treated as an expression.

Victor Nicollet
  • 24,361
  • 4
  • 58
  • 89
1

The second one works because an expression in brackets cannot be interpreted as a function declaration (so it must be a function expression, resolving the ambiguity problem with the original first expression).

lijie
  • 4,811
  • 22
  • 26