1

I've been trying to understand the following code:

var add = (function () {
        var counter = 0;
        return function () {return counter += 1;}
    })();
    add();
    add();
    add();

Here add is assigned the return value of the anonymous self calling function -- that is the function function() { return counter += 1 }. Now the first time add() is called it returns 1 as expected. But the second time add() is called it returns 2.

My question is since counter is defined inside a function so wouldn't every time the function finishes execution counter should die? That is, after the first call to add() 1 will be displayed. Now we are out of that function so shouldn't counter forget it's previous value and be destroyed from the stack like automatic variables are?

Captain Obvlious
  • 19,754
  • 5
  • 44
  • 74
user31782
  • 7,087
  • 14
  • 68
  • 143
  • 1
    http://stackoverflow.com/questions/111102/how-do-javascript-closures-work – mplungjan Apr 25 '16 at 05:19
  • Welcome to the world of closures. I suggest you play around with this concept using regular functions rather than self calling functions (IIFE) to clearly separate it from the concept of anonymous functions (early on in the late 90s to early 2000s lots of people in the community got the two mixed up to the point that some think closures can only exist inside anonymous functions. It does not help that in some other languages anonymous functions are called closures) – slebetman Apr 25 '16 at 05:22
  • The [auto] tag is specific to C++11 and does not apply her and has been removed. Please be mindful of how you tag your questions in the future. – Captain Obvlious May 05 '16 at 00:06

1 Answers1

7

What is the lifetime of variables inside a self calling function in javascript

The same as variables in any other kind of JavaScript function: They exist for as long as they can be referenced, which sometimes means long past the time the function that contains them returns.

Your counter variable continues to exist after the IIFE returns because the function it creates and returns (return function () {return counter += 1;}) is a closure over the variable. The variable will exist as long as that function exists.

More technically: Calling a function creates something called an execution context for that call, which has a variable enviroment object. Any function created during the call receives a reference to that outer variable environment object; that object, like all objects, exists as long as there's a reference to it, and so the functions keep the object alive. Variables are actually properties of that variable environment object, and so they exist as long as something references the object they're on. (This is the very simplified form.) While in theory the entire variable environment object is kept, in practice JavaScript engines are free to optimize if the effects of optimization aren't observable, so a variable that isn't actually used by the closure may (or may not) be released, depending on the engine and the code in the function.

Your IIFE can only be called once, so there can only be one counter, but it's common for a function creating a closure to be called more than once, in which case you have multiple variable objects, and multiple copies of the variables that are closed over.

Example:

function helloBuilder(name) {
  var counter = 0;
  return function() {
    ++counter;
    display("Hi there, " + name + ", this is greeting #" + counter);
  };
}

var helloFred = helloBuilder("Fred");
var helloMaria = helloBuilder("Maria");


helloFred();  // "Hi there, Fred, this is greeting #1"
helloFred();  // "Hi there, Fred, this is greeting #2"
helloMaria(); // "Hi there, Maria, this is greeting #1"
helloMaria(); // "Hi there, Maria, this is greeting #2"
helloFred();  // "Hi there, Fred, this is greeting #3"

function display(msg) {
  var p = document.createElement('p');
  p.appendChild(document.createTextNode(msg));
  document.body.appendChild(p);
}

In the above, the function returned by helloBuilder closes over both its name argument and its counter variable. (Because arguments are also stored on the execution context's variable object.) So we can see that after calling it twice, there are two variable objects, each with its own name and counter, one referenced by each function we asked helloBuilder to create.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • If I get you right then it means that since we are assigning a function to a global variable `add`. Everything inside the function is saved onto the stack, including the counter variable. So counter acts as a kind of _static_ variable. – user31782 Apr 25 '16 at 05:23
  • 1
    @user31782: Not quite. It's more that the stack itself is designed more as a linked-list rather than an array so that the stack frame can be detached and reattached when closures are created. See this answer for the conceptual low-level details of how closures are related to stacks: http://stackoverflow.com/questions/26061856/javascript-cant-access-private-properties/26063201#26063201 – slebetman Apr 25 '16 at 05:25
  • 1
    @user31782: Well, `add` doesn't have to be a global, and the contents of the variable object aren't stored on the stack. Other than that, yes. Because we keep a reference to the function the IIFE returns, the variable object for the IIFE call will be kept as long as we keep that function. And it's a *bit* like static variables in C, except that there's one *for each call to the function*. Your IIFE can only be called once, but that's specific to your example. Functions returning functions that can be called more than once are common. – T.J. Crowder Apr 25 '16 at 05:27
  • Thanks for explaining. But I haven't studied this concept so need to study the details first. – user31782 Apr 25 '16 at 05:30
  • 1
    @user31782: No worries. I added another example above. Also, I said "the contents of the variable object aren't stored on the stack" but actually, that's entirely an implementation detail. Chrome's V8 engine, for instance, initially puts local variables on the stack like C would, but then for any that are closed over, *moves* them into a heap-allocated object. But it would be perfectly valid for an implementation to make stack frames a linked list instead. At the JavaScript programming level, we don't need to think stack so much as execution context and closures. – T.J. Crowder Apr 25 '16 at 05:35