0

I am a bit new to javascript, i was just trying the below snippet:

_getUniqueID = (function () {

        var i = 1;
        return function () {
            return i++;
        };

    }());


s = _getUniqueID();
console.log(s); // 1
console.log(_getUniqueID()); // 2

I was under the impression that i would have to do s() to get 1 as the result and i was thinking that _getUniqueID() returns a function rather than execute the funtion inside it. Can somebody explain the exact execution of this function please ?

Tenali Raman
  • 380
  • 5
  • 16
  • Not sure if I understand the question, but I think it's a duplicate of [What do parentheses surrounding a JavaScript object/function/class declaration mean?](http://stackoverflow.com/q/440739/1529630) – Oriol Aug 09 '15 at 22:15
  • Possibly also a duplicate of [*How do JavaScript closures work?*](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – RobG Aug 09 '15 at 22:59
  • @TenaliRaman—I've reopened it, but it's a duplicate of [*How do JavaScript closures work?*](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) anyway so maybe you should mark it as a duplicate of that. This question has been answered many times before. – RobG Aug 10 '15 at 04:18
  • @RobG , added my own answer ! , if you still feel its a duplicate, go ahead and mark it a duplicate , I have no issues , sorry for being rude . – Tenali Raman Aug 10 '15 at 06:42

4 Answers4

2

What you're seeing here is a combination of Javascript's notion of closure combined with the pattern of an immediately invoked function expression.

I'll try to illustrate what's happening as briefly as possible:

_getUniqueID = (function () {

    var i = 1;
    return function () {
        return i++;
    };

}()); <-- The () after the closing } invokes this function immediately.

_getUniqueID is assigned the return value of this immediately invoked function expression. What gets returned from the IIFE is a function with a closure that includes that variable i. i becomes something like a private field owned by the function that returns i++ whenever it's invoked.

s = _getUniqueID();

Here the returned function (the one with the body return i++;) gets invoked and s is assigned the return value of 1.

Hope that helps. If you're new to Javascript, you should read the book "Javascript, the Good Parts". It will explain all of this in more detail.

Ghazgkull
  • 970
  • 1
  • 6
  • 17
  • 1
    By the way, there's an error in the question itself. _getUniqueID() is a function that has the variable i in its closure. Every time you invoke _getUniqueID(), the function is executed and i is incremented. So in the very last line of the question, console.log(_getUniqueID()) won't print out 1. It will print 2. – Ghazgkull Aug 09 '15 at 22:11
0
_getUniqueID = (function () {

        var i = 1;
        return function () {
            return i++;
        };

    }());


s = _getUniqueID();
console.log(s); // 1
console.log(_getUniqueID()); // 1
  1. when you do () it calls the function, a- makes function recognize i as global for this function. b- assigns function to _getUniqueID
  2. you do s = _getUniqueID();, a - it assigns s with return value of function in _getUniqueID that is 1 and makes i as 2
  3. when you do _getUniqueID() again it will call the return function again a- return 2 as the value and b makes value of i as 3.
Ekansh Rastogi
  • 2,418
  • 2
  • 14
  • 23
  • 1
    "recognize i as global for this function" --- this sounds not correct. – zerkms Aug 09 '15 at 22:18
  • *i* is held in a closure by the returned function, emulating a private variable, so is the opposite of global. – RobG Aug 09 '15 at 22:56
0

This is a pattern used in Javascript to encapsulate variables. The following functions equivalently:

var i = 1;
function increment() {
    return i ++;
}

function getUniqueId() {
    return increment();
}

But to avoid polluting the global scope with 3 names (i, increment and getUniqueId), you need to understand the following steps to refactor the above. What happens first is that the increment() function is declared locally, so it can make use of the local scope of the getUniqueId() function:

function getUniqueId() {
     var i = 0;
     var increment = function() {
          return i ++;
     };
     return increment();
}

Now the increment function can be anonymized:

function getUniqueId() {
     var i = 0;
     return function() {
          return i ++;
     }();
}

Now the outer function declaration is rewritten as a local variable declaration, which, again, avoids polluting the global scope:

var getUniqueId = function() {
     var i = 0;
     return (function() {
          return i ++;
     })();
}

You need the parentheses to have the function declaration act as an inline expression the call operator (() can operate on.

As the execution order of the inner and the outer function now no longer make a difference (i.e. getting the inner generator function and calling it, or generate the number and returning that) you can rewrite the above as

var getUniqueId = (function() {
     var i = 0;
     return function() {
          return i ++;
     };
})();

The pattern is more or less modeled after Crockford's private pattern

Gerard van Helden
  • 1,601
  • 10
  • 13
  • 1
    Minor quibble: while it's Crockford's article, it's not "his" pattern. Closures were being used to emulate private members long before it was written. – RobG Aug 09 '15 at 23:07
-2
_getUniqueID = (function () {

        var i = 1;
        return function () {
            return i++;
        };

    }());

console.log(_getUniqueID()); // 1 , this surprised me initially , I was expecting a function definition to be printed or rather _getUniqueID()() to be called in this fashion for 1 to be printed

So the above snippet of code was really confusing me because I was't understanding that the above script works in the following manner, by the time the IFFE executes _getUniqueID is essentially just the following:

_getUniqueID = function () {
           i = 1 
           return i++;
};

and hence,

_getUniqueID() // prints 1.

prints 1.

Note: please note that I understand how closures and IFFE's work.

Tenali Raman
  • 380
  • 5
  • 16