As Albert Einstein said:

If you can’t explain something to a six-year-old, then you can hardly understand.

I then tried to explain the closure of a friend of 27 years, and he did not understand anything.

How to explain closures to someone who is familiar with all the principles of programming necessary for understanding closures (functions, variables, scope, etc.), except for closures?

This question is translated from English SO.

6 answers 6

This is a translation from the community wiki .

In JavaScript, functions can be described not only one after another, but one inside the other. When you have one function inside another, then the internal function has access to the variables of the external function.

function внешняя(x) { var tmp = 3; function внутренняя(y) { alert(x + y + (++tmp)); // выведет 16 } внутренняя(10); } внешняя(2); 

This code always gives 16, because the внутренняя function sees x , which is a variable in the внешняя function. In this case, the function argument. Also внутренняя() can see tmp from внешней() .

This is called closure or closure. More precisely, the closure is called an external function, and everything inside it is called a closure environment or closure environment.

It is sometimes said that a closure is a function that returns a function, this is wrong, in order to call a function closure enough that the internal function accesses a variable from outside its scope.

 function foo(x) { var tmp = 3; return function (y) { alert(x + y + (++tmp)); // will also alert 16 } } var bar = foo(2); // bar is now a closure. bar(10); 

The above function also gives 16, because bar even after completion of foo continues to have access to x and tmp , even if the bar variable itself is not inside the scope in which they were declared.

However, since the tmp variable is still inside the closure of bar , it continues to increase with each call to bar .

Here is the simplest closure example:

 var a = 10; function test() { console.log(a); // вывод 10 console.log(b); // вывод 6 } var b = 6; test(); 

When a function is started in JavaScript, an environment is created for it, that is, a list of all the variables visible to it, not only the arguments and variables declared inside it, but also outside, in this example it is 'a' and 'b'.

You can create more than one closure in one environment, returning them as an array, an object, or linking them to global variables. In this case, they will all work with the same x or tmp value, without creating separate copies.

Since in our example x is a number, its value is copied to foo as its argument x .

JavaScript, on the other hand, always uses links when passing objects. If you called foo with an object as an argument, then the returned closure would return a reference to the original object!

 function foo(x) { var tmp = 3; return function (y) { alert(x + y + tmp); x.memb = x.memb ? x.memb + 1 : 1; alert(x.memb); } } var age = new Number(2); var bar = foo(age); // bar теперь замыкание ссылающееся на age. bar(10); 

As you might expect, each call to bar(10) increases x.memb . What you might not expect is that x continues to refer to the same object as age ! After two calls to bar , age.memb will be equal to 2! By the way, this is how memory leaks occur in HTML objects.

    A closure is the ability of a function to remember the context in which it was defined and to access it during a call. By context we mean variables that are available in the place of its definition — the function implicitly saves references to them and can then refer to them — even after the execution of the program has gone beyond their scope. Variables in this case are not collected by the garbage collector, and thanks to these implicit links, they continue to live as long as the function is alive and, accordingly, can be used by the function.

    • "ability of function to remember context" - if document.body is called from the function, then we can say that the function remembers document.body? - Stack
    • five
      document.body is not a variable, but a property of the object that we refer to using the global variable document. What I wrote is not related to properties, but only to the variables themselves. Perhaps we can say that we have captured the global variable document, but, since it is global, there is no need to capture it - it is so accessible from everywhere (except for places where its visibility will be blocked by a local variable with the same name - and in this case we could not turn to it by taking it into the circuit). So whether we close it or not - there will be no difference in practice, we will not even check it. - Vyacheslav Lapin

    A closure is the availability of variables (scope) for the current function from the parent function in which it was declared

      This is a good question!
      For a long time I did not stick what was what, although I actively used them.
      Over time, it came (sincerely hope so).
      But in two words, too, you will not tell, here is a good description of their work.
      So:
      Closures are a distant relative of encapsulation, I guess.
      In JS, only functions create scope. Therefore, when creating any function, it has two special properties (there are more of them, of course, but we do not consider them): [[scope]] (all the entities created in it are stored there - variables, arguments, functions, etc., are not available to the programmer) and __proto__ (the link to the entity in which the function is created should not be accessible at all, can only be influenced through prototype , but some browsers have successfully killed it).
      For example, when a variable is requested in a function, the interpreter searches for it in the corresponding [[scope]] , if it does not find it, then __proto__ link in __proto__ and searches its scop. Does not find - again the transition and search. And only when he is convinced that he has reached the end (the main object, the browser window ), he gives the final error that he did not find the variable.
      Because the external environment does not have access to the internal [[scope]] (it does not even know about them), it is outwardly impossible to get to the internal variables when the internal easily reach the external.

      If in a nutshell, and rude, then something like that.

         function mCounter () {
             var count = 0;
             function counter () {// create a function and increment the variable
                 count = count + 1;  // you can + =
                 return count;
             }
             return counter;  // increase the function that uses
          free variable.  This is a closure.
         }
         var dCount = mCounter (); // here we call mCounter (), we get a closure (a function with the environment)
         console.log (dCount ()); // 1 when calling dCount ()
         // the count value is taken from the count variable,
         // which is surrounded by a closure.
         console.log (dCount ()); // 2
         console.log (dCount ()); // 3
         console.log (dCount ()); // 4
         // we call the function that creates
         // another function and returns it along with the environment
         // in our case, containing the free variable count.
         // This is the closure.
         // free variable count is not associated with any values
         (therefore nazfree)
         //those.  count is declared outside the counter () function
         // in the environment where our free variable function 
         becomes closed as well
         // if we take a function with its environment, we get a closure.
        

          explain with an example.

           function func1() { var a = Math.random(); return function () { return a; } } var f = func1(); console.log(f()); var f2 = func1(); console.log(f2()); 0.34218455478549004 0.6286177076399326