0

I have an excerpt from How do JavaScript closures work?

I am having a difficult time understanding closures.

 <button type="button" id="bid">Click Me!</button> 
 <script>
 var element = document.getElementById('bid');
element.onclick = (function() {
    // init the count to 0
    var count = 0;

    return function(e) {  // <- This function becomes the onclick handler
        count++;          //    and will retain access to the above `count`

        if (count === 3) {
            // Do something every third time
            alert("Third time's the charm!");

            //Reset counter
            count = 0;
        }
    };
})();

How is the 'count' value saved between invocations? Should not it be reset every invocation by var = 0?

Community
  • 1
  • 1
Sam
  • 79
  • 6
  • 1
    possible duplicate of [How do JavaScript closures work?](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Alexis King Jan 29 '15 at 21:42
  • Think of every function as an object that has an environment; read about "lexical scope". If you reference an identifier from the environment, you create a closure. – elclanrs Jan 29 '15 at 21:42
  • It's all about the scope my friend :-) – Oscar Jan 29 '15 at 21:43
  • I think you are getting confused because there is a self calling function that returns another function. – Eyal Jan 29 '15 at 21:52

6 Answers6

1

Before answering to your question,first lets discuss how your code works :

When you define a function inside another function it creates a clouser.Inside a clouser the inside functions can access the outer functions scope, i mean outer function's variable and argument even if the outer function has returned. In your code the outer function is an immediately-invoked-function .That means it is invoked immediately just after it is defined. When it returns , the inside function is assigned to the onclick event.The click function can access ,as well as modify the outer function's variable (in this case count which is defined in the outer function) even if it returned. I have commented out in your code.Go through it,it will be clear

First, immediately invoked function (function(){...})() will invoked immediately.It returns another function.So what is left is a returned function which will be assigned to the onclik handler. So,after return it will be

 var element = document.getElementById('bid');
    element.onclick =function(e) {  // <- This returned function has becomes the onclick handler
            count++;          //  it can access the outer function's count variable and modify it even if the outer function returns.

            if (count === 3) {
                // Do something every third time
                alert("Third time's the charm!");

                //Reset counter
                count = 0;  // it can also reset outer function's count variable to zero
            }
        };

How is 'count' value save between invokations? Should not it be reset every invokation by var = 0?

Right. If you use this code again and again along with immediately invoked function every time count will begin with zero.But you can see the beauty of it if you keep clicking the same button again and again.Even if the outer function has returned ,inner function has access to its variables.So they will get modified every time you click the button

first click to button will print 1,So count is now 1. second click will modify it again and will print 2 and so on.Remember in clousers inner function can access outer function's variable even if outer function returns.So,inner function doesn't have any count variable.It is just accessing outer scope's variable.So,after third click it will assigned to zero again.

 var element = document.getElementById('bid');
 var mydiv=document.getElementById('mydiv');

element.onclick = (function() {

// init the count to 0
var count = 0;

return function(e) {  // <- This function becomes the onclick handler
    count++; 
   mydiv.innerHTML+=count+'</br>';  //    and will retain access to the above `count`

    if (count === 3) {
        // Do something every third time
        mydiv.innerHTML +="Third time's the charm!</br>";

        //Reset counter
        count = 0;
    }
};
})();
 <button type="button" id="bid">keep clicking me </button> 
   <div id='mydiv'></div>
AL-zami
  • 8,902
  • 15
  • 71
  • 130
0

If it were declared like this:

element.onclick = function() {
  var count = 0;
};

… you're correct that count would be initialized to 0 for every click.

However, it's declared like this:

element.onclick = (function() {
  var count = 0;
  return function(e) {
    count++;
    ...
  };
})();

In this case, the onclick handler has been assigned to the result of the function, which is:

return function(e) {
  count++;
  ...
};

So count is not initialized to 0 during a click event.

count is local to the first function in the code. Since the second function is within that function, count is available to it.

Rick Hitchcock
  • 35,202
  • 5
  • 48
  • 79
0

As you said, your function becomes the onclick handler and the assignent of count is only executed once (when your function is created and assigned to the click handler). The count is still in scope of the function, i.e., the function keeps a reference and uses that one. Therefore, it's not reset and incrementing.

0

The outer function, the one enclosed in parentheses, is an example of an Immediately Invoked Function Expression. That function is being both defined and invoked at once and its return value is what is being assigned to element.onclick.

So why bother with that when we could've just set element.onclick to the inner function directly? Well, that has to do with JavaScript scoping rules. The only way to get a private scope is by wrapping something in a function. Here, count is declared and initialized in the outer function, effectively making it private. The inner function can still access and manipulate it. That's all that's meant by the term closure -- an inner function accessing its enclosing function's variables.

The outer function is called just once (immediately) so count is only ever initialized to 0 once. But the variable remains in memory and won't be garbage collected because JavaScript is smart enough to know that the inner function still needs access to it.

vrmc
  • 321
  • 1
  • 6
0

The way I like to think about:

        var count = 0;//Belongs to the window 
        //object and I like to imagine a window object 
        //around it so that you can see 
        //that everything in javascript is enclosed!

        function() {count++};

I am pretty sure you don't have any difficulties understanding the above code. Now imagine the following:

          var count = 0; //Belongs to the window 

          function x() {
              var count = 0;//Private to function x
              (function () {
                  count++;
                  alert(count);//What will this output?
              })();
          };

          x();
          alert(count);//And this?

You will see that the first will output 1 and the second 0, why: because they are different variables. They have nothing to do with each other. That is the reason why people like to make closures in javascript. If you pollute the global name space it can be overwritten.

          var count = 0; //Belongs to the window 


          function x() {
              var count = 0;
              (function () {
                  count++;
                  alert(count);
              })();
          };

          x();
          alert(count);
          var count= 1;//Global count has now been overwritten
          alert(count);
Michelangelo
  • 5,888
  • 5
  • 31
  • 50
0

You declare an immediately invoking function with the syntax:

(function() {
    ...
})();

This runs only once, when first loaded.

The code returned:

return function(e) {  // <- This function becomes the onclick handler
    count++;          //    and will retain access to the above `count`

    if (count === 3) {
        // Do something every third time
        alert("Third time's the charm!");

        //Reset counter
        count = 0;
    }
};

is what actually becomes the click handler. So only the code within the returned function is run on each click.

Because of the way that scope is handled in Javascript, the inner function has access to the variables in the outer function. You could accomplish similar functionality by making the count variable global, but the nice thing about this pattern is that it limits your global variables, and also gives variables privacy. No calls from outside of your immediately invoking function will be able to access count.

JammGamm
  • 151
  • 1
  • 5