1

Why/when do we need extra brackets in function expressions. These two pieces of code return same result. Any context where we need the extra ()?

// without brackets
var y = function (x) { return x * x; }(4) + 1;
console.log(y);

// with brackets
var y = (function (x) { return x * x; }(4)) + 1;
console.log(y);

Thanks

cmutex
  • 953
  • 5
  • 14
  • In general, when you want to change the order of operation or to force an (ambiguous) construct to be evaluated as expression. – Felix Kling Dec 29 '13 at 19:43

1 Answers1

4

You only need the parentheses (which are not "extra," since you need them!) when the parser is in a state where it's expecting a statement rather than an expression. So if you think in terms of: "Could I start an if statement here?", if the answer is "Yes, I could" then you need the parens.

The reason is that when the parser is expecting a statement, if it sees the keyword function, it assumes what follows is a function declaration, not a function expression.

To make the parser expect an expression, we don't have to use parens, any token that will make the parser expect an expression works. More information on that in this other answer.

So you don't need them after an =, for instance (your example), because the parser is already expecting an expression on the right-hand side of the assignment. Similarly you don't need them after the : in a property initializer:

var obj = {
    foo: function() { /* ... */ }
};

...or when passing a function expression into a function as an argument:

foo(function() {
    /* ... */
});

...that sort of thing.

But you need them here:

doSomething();
function() { /* ... */}();   // <== Fails

...because when it sees function, the parser thinks it's going to be a function declaration, so:

doSomething();
(function() { /* ... */})(); // <== Works

Or

doSomething();
(function() { /* ... */}()); // <== Works
// Subtle diff here ----^^^

Or some more obscure examples:

doSomething();
+function() { /* ... */}();  // <== Works

doSomething();
!function() { /* ... */}();  // <== Works

doSomething();
~function() { /* ... */}();  // <== Works
Community
  • 1
  • 1
T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
  • 1
    +1, but "when the parser is in a state..." is somewhat opaque. I realize quoting the spec might not be realistic here, but still. – Jon Dec 29 '13 at 19:46
  • 1
    I must say I like this "can I `if`" rule very much. Level capped teaching aid! – Jon Dec 29 '13 at 19:51
  • Thanks. But can't the parser infer that it is a function expression by noting that there is a "()" after "}"? – cmutex Dec 29 '13 at 19:55
  • @user3124390: It doesn't look that far ahead, and moreover, if you have `function foo() { }();` that isn't a function expression, it's a function declaration followed by an empty pair of parens (which is perfectly valid, but doesn't call the function). And of course they may not be empty, you might be doing this: `function foo() { }(function() { console.log("Run me!"); }())` which is, again, a *declaration* followed by an expression unrelated to the declaration. So we resolve the ambiguity by forcing an expression. (Is it perfect? No. :-) No human creation is ever perfect: JS is no exception.) – T.J. Crowder Dec 29 '13 at 20:00
  • isn't this also supposed to use, when you like to make a function anonymous so it can not be referenced outside? – xhallix Dec 29 '13 at 20:02