3

Can anyone explain me the following function inside a JS file

function Init()
{
  (function set()
     {
       -----code---
       print "hello";
      }
   )();
}

If I call the function Init , does it automatically run the function set as well or i need to call set() to run it?

user3466034
  • 107
  • 1
  • 1
  • 6
  • Yes, because its an IIFE that defines a scope around your code. In your case it can make no difference because Init already created a scope. – Blauharley Jan 23 '17 at 20:05

4 Answers4

1

You need to call Init to run any code inside of it. Now, that code inside is just regular JavaScript code, but an interesting one. Let's see why.


How

Your inner function is a so-called IIFE. What you can do to make it easier to read the outer function (Init), is to replace the inner function with the result of the IIFE call.

Here are a few examples:

var x = undefined; // x === undefined
x = (undefined); // again
x = 3;      // x === 3
x = (3);   // again the same
x = 'some string'; // some string
x = ('some string'); // the same

So it's ok to put () around an object, you get the same object. The same for a function

x = function() {};   // x is that function now.
x = (function() {}); // the same.

But if you say x = 3;, can you call x?

x = 3;
x(); // syntax error
x = (3);
x(); // again error. can't call a number.

But, if your x is a function, you can call it:

x = function() { console.log('Hi'); }; // you can call x now.
x(); // logs 'Hi'!

So if you do the same with parenthesis, it's the same:

x = (function() { console.log('Hi'); }); // again, the same.
x(); // no error, function called again!

So you can skip the assignment part:

// instead of x = (...); and the x(), you replace the x part right away.

(function() { console.log('Hi'); })()
// function body       up to here ^^ now the call part.

Note that it won't work without the first pair of parens:

function() { console.log('Hi'); }(); // syntax error.

So you're putting the outer parens () just to cast that function expression into an object in-place.


Why

So that's how it works. But why? Because you wanna make sure nobody else calls your function! If you do this:

var x = function() {};
x();

Now there are at least two things that can happen that you might not want:

  1. There might be a name clash. You might not know if there's an "x" already defined on wherever the outer function is gonna be called at, e.g. you bind Init to some object which has x at scope or something.

  2. Somebody can "steal" your x and call it again. Not necessarily steal, you just leak it (a subtle bug) and some other code calls x, expecting to find its own x, but in fact, it's your x now because it is reachable. And you wanted it not to be.

So you handily lock it away in anonymous function that's executed right away.

Hope this clears things a bit.

Zlatko
  • 18,936
  • 14
  • 70
  • 123
  • "*So you're putting the outer parens () just to cast that function def into an object in-place.*". Actually, the outer parenthesis changes what might be a function declaration into a function expression. Any punctuator can be used that is allowed at the start of a statement, e.g. `+`, `-` or `!` as in `!function(){}()`. ;-) – RobG Jan 23 '17 at 20:40
  • @RobG Awesome! TIL !function() { console.log('a'); }() https://twitter.com/zladuric/status/823632051572248577 – Zlatko Jan 23 '17 at 20:41
  • Yep, saves one character over (function(){}()). ;-) – RobG Jan 23 '17 at 23:08
0

You would need to call Init(); to execute the function.

The (function () {console.log('IIFE') }());

Syntax you are referring to is an immediately-invoked function expression.

Darren
  • 68,902
  • 24
  • 138
  • 144
0

this is a basic function closure in js (an inner function inside another one).

also.. it is anonymous function..meaning...you can only use that function once (and that is why the function call is attached to function deceleration). so...

function regular()
{
    function regular_closure()
    {

    }

    (function () // this is anonymous
    {

    })(); // call the anonymous function.. which is also a closure

    regular_closure(); // call the function
}

more about this topic:

MDN - js closures in depth

When to use js closure

Community
  • 1
  • 1
ymz
  • 6,602
  • 1
  • 20
  • 39
  • I think calling this a closure is misleading. Every function has a closure the variables in its outer execution contexts, not just immediately invoked functions. The function is executed every time *regular* is called, so not really only used once and it's a function expression, not a declaration. – RobG Jan 23 '17 at 20:35
  • Yep, this is a closure, but I think the question doesn't touch on closure per se. There's nothing accessed from the closure so it's not so relevant. – Zlatko Jan 23 '17 at 20:36
  • that is actually why i attached the link from MDN :) – ymz Jan 23 '17 at 20:37
  • The link is to closure. Closure is not a relevant part of it, I would say, and I think @RobG would agree? – Zlatko Jan 23 '17 at 20:38
0

When you do

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

, it is a close equivalent to

var set = function () { /*code here*/ };
set();

So when you call Init(), the set function will be called.

Dominique Fortin
  • 2,212
  • 15
  • 20
  • I'd say it's not technically equal. In the first example, there are no objects left at the current scope after the call. In the second example, you have a `set` variable in the code above and bellow the call (and it's not even undefined bellow). – Zlatko Jan 23 '17 at 20:35
  • @Zlatko `In the first example, there are no objects left at the current scope` That's false. In the first example, you can call set() anywhere within the function Init and it will work, as opposed to the second where you can only call set() after the assignment. Even in the case of an anonymous function, an internal name was created for it within the environment of the Init's scope and that before it even started to interprete the first line of the function Init. – Dominique Fortin Jan 24 '17 at 14:40
  • nope, `set` is not available in the outer function scope or anywhere outside `set` itself. Check this out: https://gist.github.com/zladuric/dae9dc89297921f4f4023dee53e667fd Or did I understand you incorectly? – Zlatko Jan 24 '17 at 15:19
  • 1
    @Zlatko I was wrong. I found the reference in the spec: `... unlike in a FunctionDeclaration, the Identifier in a FunctionExpression cannot be referenced from and does not affect the scope enclosing the FunctionExpression.` – Dominique Fortin Jan 24 '17 at 16:01