15

I am reading this book and it has this code example

function getFunction() {
    var result = [];
    for (var i = 0; i < 10; i++) {
        result[i] = function(num) {
            return function() {
                console.log("this is " + num);
            }
        }(i);
    };

    return result;
}

It is working OK but why the anonymous function here not wrapped in parenthesis like this (function(...))(i); ? And in which cases can parenthesis be omitted in anonymous function?

Johnny Chen
  • 2,025
  • 1
  • 18
  • 27
  • Note that there are other ways to cause a function to be an expression. For example: `!function(){}()` or `0/function(){}()` or my favorite `-function(){}()` – slebetman Jul 08 '15 at 08:55
  • Also see [why the parenthesis are necessary](http://stackoverflow.com/q/1634268/1048572) in other places. – Bergi Jul 08 '15 at 13:53

4 Answers4

18

Since the syntax for function declarations and function expressions is identical, JS tells which one you are using from the code around the function.

To stop it being a function declaration you need to use it in an expression. Wrapping it in parenthesis will will do that but preceding it with a = will too (as will a host of other operators). Since there is a = here, the parenthesis are unnecessary.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
8

Since it's used as a second operand for the assignment operator = JS engine can for sure treat it as a function expression.

Which is not the case when you define an anonymous function standalone: in that case you need to help engine to treat it as an expression, not as a statement.

zerkms
  • 249,484
  • 69
  • 436
  • 539
4

Regular function declaration looks like this:

function FuncName() { doSomething(); }

Then you can call this function like this:

FuncName();

Anonymous functions are very similar:

var FuncName = function YouCanEvenPutANameHereAndItWillBeIgnored() { doSomething(); }

If the syntax for regular functions and anonymous functions is identical, then how does JS distinguish them? It deduces what you mean from context. That's why this Instantly Invoked Function Expression won't work:

function(s) { console.log(s); } ('abc');

JS parser reads it from left. The line starts with function, so JS guesses it's a regular function declaration and expects it to end with }. There's ('abc') after the function, though, and JS throws an error.

To fix it, you have to trick JS into parsing that function as an anonymous function. To do that you have to make it part of an expression. The most popular way is this:

(function(s) { console.log(s); }) ('abc');

There are other ways, though. They are less readable, but they work too.

( function(s) { console.log(s); } ('abc') );
+function(s) { console.log(s); } ('abc');
-function(s) { console.log(s); } ('abc');
1 * function(s) { console.log(s); } ('abc');

In your case the function is already a part of an expression, so there's no need to add parentheses.

gronostaj
  • 2,231
  • 2
  • 23
  • 43
  • 1
    The reason that the line starting with `function` is a parse error is because the function has no name. `function log(s) { console.log(s); } (function(s) { console.log(s); } ('abc'))` declares a function `log` and then logs `abc`. Wrap it in brackets however and it executes instead of declaring. Also `!` is often used to make the code parse as an expression, it interacts well with automatic semicolon insertion. – Neil Jul 10 '15 at 00:19
2

These are immediately invoked function expressions (IIFE). they can be used anywhere that an expression is expected. examples are on the right hand side of an equal sign or either side of a comparison operator or even as an argument for another function. Where the parenthesis are needed is if they are used where an expression is not expected. such as in the following example

var a=1;
(function(b){
  a=b;
})(2);
console.log(a);

Which outputs 2.

Anywhere an expression is expected the following are equivalent

function(a){....}(b);

(function(a){....})(b);

(function(a){....}(b));

The parenthesis are however considered a best practice because they "hint" at the fact that it is a immediately invoked function without having to scroll down to the end of the function.

Dean Brown
  • 156
  • 4