Wen pointed out that in segmentfault.com/a/119000000…

Refer to the article segmentfault.com/a/119000001…

To understand closures, you first need to understand the concepts of execution environment, active objects, and scope chains

Execution Context (EC) and active objects

The execution environment is also called the execution context

There are three types of execution environment (window, function execution environment, evel() execution environment)

Js associates a variable object with each execution environment. All variables and functions defined in the environment are stored in this object

  • Generation: The execution environment and variable objects are generated when the function is run

  • Destroy: After all code in the execution environment is executed, the execution environment is destroyed, along with the variables and functions stored in it. (The global execution environment is destroyed when the application exits)

The scope chain

When code is executed in an execution environment, a scope chain of variable objects is created, which specifies the order in which all variables and functions are accessed by the execution environment. Scope chain of the front, is always the current code execution environment variable object, if the environment is function, is the active object is variable object scope chain under a variable object, from the external environment, then the next variable object, from the next external environment, and so on until a global execution environment In the function implementation process, Variables are searched layer by layer and identifiers are resolved according to the scope chain of the current execution environment

Do you think the above theory is boring and difficult? Because basically quote from the book, do not worry to understand, placed above first, and so on combined with the case to look back! Here’s an example:

The sample1
<script>
    var a = 2;
    function A(){
         var a = 1;
         return a ;
    }
    console.log(A());/ / 1
</script>
Copy the code

Take this simple code as an example and draw a diagram (drawn directly in Photoshop, forgive my poor handwriting) based on the above theory:

, as shown in A executive function, created A execution environment and the variable object, including A variable objects and global variables contain A variable in the object, according to the scope chain to find from the front to rear, found in A variable object, so the output 1, execution is completed, the execution of A environmental destruction, A variable object with no citations, so also destroyed;

The sample 2

<script>
    function A(){
         var a = 1;
         return a ;
    }
    console.log(a);// a is not defined
</script>  
Copy the code

This example is relatively simple, to draw the words only need to draw a global variable pair, because in JS, the peripheral environment can not access the inner local variable (in fact, the essence of the scope chain can not find the corresponding value), so the variable undefined error will be reported. Sample 3

<script>
      function A(){
         var a = 1;
         function B(){
             if(a==1) {console.log(1)}else
             {
                  console.log(0);
              }
         }
         B();
    }
    A();/ / 1
</script>  

Copy the code

It is clear from the figure that variable objects can be accessed in each execution environment, so B can access A’s variable objects, the variables in the global variable objects and its own variable objects, and A can access its own variable objects and the global variable objects

So much for execution environments and scope chains, let’s get down to business, closures;

Early closure

A closure is a function that has access to another function’s scope variable. The usual way to create a closure is to create another function inside a function

As mentioned above, due to the structure of the scope chain, peripheral functions cannot access the inner variables. In order to access the inner variables, we can use the closure **. The essence of the closure is still function. **

The sample4
<script>
    function A(){
        var x = 1;
        return function(){
            console.log(x); }}var m = A();
    m();/ / 1
</script>




Copy the code

Above is A very simple closure example, using m function, we can obtain the value of the internal variable of function A, this example is relatively simple, do not see any problems, let’s take A closer look. (Solved the problem of not being able to get values outside the function)

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — – from the simple to the complex line, please get ready — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — –

The closure,

Difficulty 1: determine whether the variable objects that the scope points to are the same

The sample 5

function A(){ var x = 1; return function(){ x++; console.log(x); } } var m1 = A(); // execute m1() for the first time; //2 m1(); //3 var m2 = A(); // execute A m2() the second time; //2 m1(); //4 </script>Copy the code

The above example can lead to several questions: 1. Why is the value of x increasing when m1 is executed continuously? 2. When defining m2, why does x start at 1 again? 3. After running M2, why run M1 again? X continues to increase according to the previous running results of M1? (In fact, why are the x in M1 and M2 independent and maintained separately?)

In fact, to solve the above problem, we need to use the previous knowledge: first, draw the structure diagram,

Don’t panic. It’s a little messy, but it’s actually very simple: the left half is exactly the same as the simple closure example above, and the right half is exactly symmetric with the left; Focus on attention to look at the picture: every time to perform A function, will generate an A activity variables and execution environment, implementation is completed, A execution environment destroyed, but the active object by closure function reference, so still, so eventually the remaining two variables of A object, so the m1 and m2 in the operation of the x, pointing to A different data,

Now answer the above three questions: 1.(why is x increasing when m1 is executed continuously?) Answer: The value of x is increasing because the active object A referenced by M1 has not been released (m1=null if you want to release it). 2. When defining m2, why does x start at 1 again? Answer: The scope chain of M2 refers to A new x value because function A is run again, generating A new active object of A. 3. Why are x in M1 and M2 independent and maintained separately? Answer: Because when m1 and m2 are defined, function A is respectively run to generate two active objects, so the scope chain of M1 and M2 points to different active objects of A.

Ok, so let’s review the previous points:

  • The execution environment and variable objects are generated when the function is run
  • After all the code in the execution environment is executed, the execution environment is destroyed, along with the variables and functions stored in it. (The global execution environment is destroyed when the application exits)

Does that make sense? Let’s look at another very similar example:

The sample of 6

 <script>
    function A(){
        var x = 1;
        var m=[];
        m[0] = function(){
            x++;
            console.log(x);
        };
        m[1] = function(){
            x++;
            console.log(x);
        }
         return m;
    }
    var m = A();// Run A for the first time and only this time
    m[0] ();/ / 2
    m[1] ();/ / 3
    m[0] ();/ / 4
    m[1] ();/ / 5
</script>
Copy the code

This example is very similar to the above example, except that the first two functions are defined inside A, and the final result is somewhat different from the above example: The variable x is still increasing, but the function defined by m[0] and m[1] is no longer independent of each other. In fact, you can guess that the scope of m[0] and m[1] refers to the same variable object of A. Why? This code calls function A only once.

The execution environment and variable objects are generated when the function is run

Since A is executed only once, the active variable of A is of course also generated, so here the scope of m[0] and m[1] refer to the same variable object of A

Difficulty 2: Judge the value of the variable in the variable object

The sample 7

 <script>
    function A(){
        var funs=[];
        for(var i=0; i<10; i++){ funs[i]=function(){
               return i;
           }
              console.log(i) 
        }
        return funs; 
    }
    var funs = A();// define funs[0]-funs[9], 10 functions
     Fun [0],fun[0],fun[6
    console.log(funs[0] ());/ / 10
    console.log(funs[1] ());/ / 10
    console.log(funs[6] ());/ / 10
</script>

Copy the code

Funs [0]-funs[9] is the same as funs[0], funs[9] is the same as funs[0]-funs[9].

The execution environment and variable objects are generated when the function is run

So, when var funs = A(); The actual time to generate the environment variable is in console.log(funs0); What is the value of I in the variable object of A? It’s very simple, if you look at it when it returns, the value of I, obviously, the value of I is 10, so the last three sentences output 10

Ok, in the above case, if I want fun[I] to return I, what should I say? In javascript Advanced Programming, a reference is provided:

The sample of eight

 <script>
    function A(){
        var funs=[];
        for(var i=0; i<10; i++){ funs[i] =function anonymous1(num){
                        return function anonymous2(){
                    return num;
                }
            }(i);
        }
        return funs; 
    }
    var funs = A();// define funs[0]-funs[9], 10 functions
    console.log(funs[0] ());/ / 0
    console.log(funs[1] ());/ / 1
    console.log(funs[6] ());/ / 6
</script>
Copy the code

Doesn’t it look big? It doesn’t matter, next we will slowly analyze, of course, the above code anonymous1 and anonymous2 two names are added by myself, in order to better explain later. Function anonymous1(num){}(I) function anonymous1(num){}(I) Anonymous2: < div style = “font-size: 10.0pt; line-height: 20px

The execution environment and variable objects are generated when the function is run

Ok, so please answer me: how many anonymous1 activity variables are generated here? Answer: 10 of course, how many num values are stored in each anonymous1 activity variable? Answer: When looking at the return of anonymous function, it can be seen that the stored num value is the I value passed in each time, namely 0-9

Ok, so now it’s clear that this is essentially the same thing as anonymous1 anonymous1 activity clock saving each I value for use by the innermost anonymous2 function