This question has already been answered:

What is clear to me is closure, but in the course of their research there were some nuances:

There is a code:

<script> function createCounter() { var numberOfCalls = 0; return function() { return ++numberOfCalls; } } var fn = createCounter(); alert(fn()); //1 alert(fn()); //2 alert(fn()); //3 </script> 

I can not realize why the variable numberOfCalls in the createCounter function is not reset? Is this a trick or is there a reasonable explanation?

Reported as a duplicate by Grundy , aleksandr barakin , VenZell , Dmitriy Simushev , Pavel Mayorov members on Apr 29 '16 at 10:03 .

A similar question was asked earlier and an answer has already been received. If the answers provided are not exhaustive, please ask a new question .

  • one
    Do you have a reasonable explanation why it should be reset? Or is this a trick? - Darth
  • It seems to me that each time the function is called, the variable must be initialized to zero, as it should be written in the code, but in fact it is not. it's hard to realize after C ++ language - perfect
  • one
    This is what happens. You call a function once, it is initialized to zero. Then you call another function three times, which increases its value by one. - Darth
  • So all this is a trick. I just did not understand why such a mechanism for holding values ​​is invented, when properties that retain their values ​​can be used for a function. PS in С ++ there is a static keyword for this and in javascript the whole construction is dedicated to it ( - perfect
  • one
    No, this is not an analogue of static values. Well, maybe remotely, of course. - user207618

3 answers 3

"You call the createCounter function createCounter ."

"Closure" - the creation of an object containing instances of all variables from external scopes used by the function.

Call the function again, and then start calling the two results in a random order:

 $(document).ready(function() { function createCounter() { var numberOfCalls = 0; return function() { return ++numberOfCalls; }; } function appendOutput(aText) { $("#output").append(aText + "<br/>"); } $("#btnRun").click(function() { $("#output").html(""); var fn1 = createCounter(); var fn2 = createCounter(); appendOutput("fn1: " + fn1()); appendOutput("fn1: " + fn1()); appendOutput("fn1: " + fn1()); appendOutput("fn2: " + fn2()); appendOutput("fn2: " + fn2()); appendOutput("fn1: " + fn1()); }); }); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <button type="button" id="btnRun">Run</button> <div id="output">output</div> 

    Its [variable] was initialized once, the returned function is nested, and since the variable is used in the function, the collector does not remove it.
    Useful reading why this happens .

      The feature of nested functions is to get values ​​from it. In this case, another function is created inside one function and returned as a result. In the development of interfaces, this is a completely standard technique, the function can then be assigned as a handler for the visitor's actions.

       function createCounter() { // LexicalEnvironment = { numberOfCalls: undefined } var numberOfCalls = 0; // LexicalEnvironment = { numberOfCalls : 0 } return function() { // [[Scope]] -> LexicalEnvironment (**) return numberOfCalls++; }; } 

      As you can see, we received an independent function() counter, each of which, in an unnoticeable way, saves the current number of calls.

      If you describe in more detail what is happening:

      1) The line (*) starts createCounter() . This creates a LexicalEnvironment for the variables of the current call. The function has one variable, var numberOfCalls , which will become a property of this object. It is initially initialized to undefined , then in the process of execution it will receive the value 0.

      2) During execution, createCounter() creates a function in the (**) line. When created, this function gets the [[Scope]] internal property with reference to the current LexicalEnvironment .

      3) Next, the createCounter() call is completed.