Preface:

Introductory article here about closures, preliminary introduction of the concept of closure, in this article there is the case of a counter, if you want to take into account the security counter variable and the realization of the counting function, use a closure is a good way About the realization of the counter method, this article finally provides another way of thinking: using the function object properties, bala bala

The body of the

Closure three elements 1. Nested functions 2. Inner functions access variables of outer functions 3. Call an internal function in addition to an external function

role

1. Make local variables privatized permanent variables 2. Pass arguments to functions called by events

    <script>
        function f(){
            var x = 1;
            function e(){
                x++;
                console.log(x);
            }
            return e;// Return the pointer to the inner function, so that e can be obtained in addition to the outer function
        }
        var e = f();
        e();// call once, count once,x increment once
    </script>
Copy the code

Or an inner function can be assigned to a global variable, expanding the scope so that the inner function can be called in the context

    <script>
    	var e;
        function f(){
            var x = 1;
            e = function (){
                x++;
                console.log(x);
            }/ / global
        }
        f();
        e();// Call once, count once
    </script>
Copy the code

You can also have multiple internal functions that operate on the same variable as the external function

    <script>
        var e1;
        var e2;
        function f(){
            var x = 1;
            e1 = function (){
                x++;
                console.log(x);
            }
            e2 = function(){
                x--;
                console.log(x);
            }
        }
        f();
        e1();// Call once, count once
    </script>
Copy the code

Running results:

What exactly is a closure?

conceptA closure consists of a function and the syntactic environment in which the function was created, which contains all local variables accessible at the time the closure was created

It’s like having a simple class feature:

Closure operations can be viewed as closure factories and closure objects.

Closure objects are generated by closure factories, and each closure object does not interfere with each other.

Closure objects store factory-given local variables, and a function that has a pointer to the function in the closure object. Use this function;

Closure objects are stored in memory until they are not used for a long time and are automatically reclaimed by the system; (So that x doesn’t expire at the end of f.)

		// Closure factory (function)
        function f(){
            var x = 1;
            function e(){
                x++;
                console.log(x);
            }
            return e;
        }
        var f1 = f();// Closure object 1
        var f2 = f();// Closure object 2
Copy the code

After executing f1 for 3 times, the value of x in f1 has reached 4. At this point, execute f2 once, and print x as 2

Common mistakes

Scenario: Use the same closure object within a loop, causing variables to accumulate

    <ul>
        <li>li1</li>
        <li>li2</li>
        <li>li3</li>
    </ul>
    <script>
        function showId(id){
            console.log(id);
        }
        function setClick(){
            var ary = document.getElementsByTagName('li');
            for (var i = 0; i < ary.length; i++){
                ary[i].onclick = function(){
                    showId(i+1);
                }
                
            }
        }
        setClick();

    </script>
Copy the code

The results: No matter which li is clicked, the output is 4



parsing:

The setClick function satisfies the elements of a closure. The anonymous function inside uses the variable I created by the external function, and the for loop above results in:



As you can see, after the setClick function is executed, I has become 3 and is stored in memory, so when we click on one of the li’s, showId comes out with 4’s

We can solve this problem in two ways

Method one: Use closure factories to create multiple closure objects

        function showId(id){
            console.log(id);
        }

        function clickFunc(id){
            function e(){
                showId(id);
            }
            return e;
        }
        function setClick(){
            var ary = document.getElementsByTagName('li');
            for (var i = 0; i < ary.length; i++){
                ary[i].onclick = clickFunc(i + 1);
                
            }
        }
        setClick();
Copy the code

Running effect:

\

Method 2: Create multiple closure objects using immediate execution functions

		function showId(id){
            console.log(id);
        }
        
        function setClick(){
            var ary = document.getElementsByTagName('li');
            for (var i = 0; i < ary.length; i++){
                (function (){
                    var id = i;
                    ary[id].onclick = function(){
                        showId(id + 1); }}) (); }}Copy the code

The effect same as above: Debugging is as follows:

Or not using closures

        function setClick(){
            var ary = document.getElementsByTagName('li');
            for (var i = 0; i < ary.length; i++){
                
                    let id = i;
                    ary[id].onclick = function(){
                        showId(id + 1); }}}Copy the code

The result is the same as above, and so is the onclick function of each li.

SetClick is a closure factory. Its local variable I is in the same closure object as ary[I]. Onclick.

When we click on one of the li’s, showId gets the argument I +1=3+1=4. After I reaches 3, the closure no longer stores the summing result, so showId’s I is always 3.

If we separate I from ID, we can avoid the effect of I accumulation on the internal function parameters. If we create multiple closure objects (ID1,ID2,ID3) inside the inner function of setClick,I will remain, but does not affect the closure object id parameter loop, as I accumulation, and create closure object. I +1 has been passed to the variable ID

Therefore, if you do not want the accumulation of I to affect the inner function when using the for loop to pass parameters to the inner function, the simple way is to use immediate execution or directly define a variable with let to separate the direct connection between the inner function and the external variable

If there is a more convincing understanding, I will update