Thoroughly understand closures through examples

Thoroughly understand closures through examples

In JS, closure and asynchrony are called two major difficulties. What is a closure and what is the function of a closure?
Before we talk about closures, let's take a look at variable scope. There are two types of variables according to their scope: global variables and local variables. There are mainly the following points:

  1. Variables inside the function are called local variables, and those outside the function are called global variables.
  2. Global variables can be used inside functions, but local variables cannot be used outside functions.
  3. When the function is executed, the local variables in this scope will be destroyed immediately

What is a closure?

In Advanced JavaScript Programming, a closure is defined as a function that has access to variables in the scope of another function. That is: a closure is a function

It can be simply understood as: If there is a local variable inside a function, and other global scope or local scope can access this variable, a closure will be generated, and the function where the accessed variable is located is called a closure function.

for example:

function fn() {
	var num = 10;
	function fun() {
		console.log(num);
	}
	fun();
}
fn();   //10

During the execution of the above code, the scope of the function fun accesses the local variable num in the scope of another function fn, and a closure is generated at this time. The generated closure fn can be seen from the chrom browser breakpoint debug window.

Now slightly modify the above code:

function fn() {
	var num = 10;
	return function() {
		console.log(num);
	}
}
var f = fn();   //10
f();

The execution process is equivalent to:

var f = function() {
		console.log(num);
	}    //This real f is a function, which stores an anonymous function.
f();  //10

During execution, a function outside the scope of fn accesses the local variable num within the scope of fn, resulting in a closure, and the closure function is still fn.

What does a closure do?

Under normal circumstances, the variables in a function can only be used in this function, and the local variables are destroyed immediately after the function is executed.
However, in the above code, the local variable num in fn can also be used by the f function outside its scope, and num is not destroyed immediately after fn() is executed, but is destroyed after f() is also executed.
So it's not hard to come to the conclusion that closures can extend the scope of variables.

Closure case

Case 1: Output the index value corresponding to the current li when clicking the li label to input.

<nav>
	<ul>
	    <li>apple</li>
	    <li>banana</li>
	    <li>Grape</li>
	    <li>Pineapple</li>
	</ul>
</nav>
<script>
	var lis = document.querySelectorAll('li');
	for(var i = 0; i < lis.length; i++) {
	            lis[i].onclick = function() {
	                console.log(i);
	            }
	        }
</script>

After the above code is executed, it will be found that no matter which li tag is clicked, the output index value is 4. This is because the function in onclick is an asynchronous task, which will only be triggered when it is clicked, and the onclick will be skipped directly when the for loop is executed. The function.
Now combine it with the immediate execution function to achieve:

<script>
	for(var i = 0; i < lis.length; i++) {
	            (function(i) {
	                lis[i].onclick = function() {
	                console.log(i);
	            }
	            })(i);
	        }
</script>

In the modified code, an immediate execution function is generated each time the loop is clicked. After clicking, the function in onclick accesses the variable i received by the immediate execution function, and outputs the current index value. In this process, a closure is generated, which can be inferred. Closures are functions that execute immediately. Immediately executed functions are also known as small closures because any function within the function can use the arguments it passes.

However, it will be found that the above code will generate an immediate execution function in each loop, which will reduce the efficiency. At the same time, the variable i in the immediate execution function is not destroyed immediately after the function is executed, but waits for the function in onclick. It will be destroyed after the execution is completed. If it is not clicked, it will cause a memory leak. It would be more ideal to use the new let attribute in ES6 to achieve this functionality. Therefore, in actual development, it is necessary to judge whether to use closures according to the actual situation.

Case 2: Click on the li tag, and output all li elements after 5 seconds

for (var i = 0; i < lis.length; i++) {
        (function(i){
            setTimeout(function () {
            console.log(lis[i].innerHTML);
        },5000);
        })(i);
    }

The callback function in the timer here and the callback function in onclick in Case 1 are both asynchronous tasks, which will only be executed when triggered, that is, after 5 seconds, while the synchronous task in the for loop will be executed immediately. So it needs to be put into an immediate function.
In this process, the scope of the function in the timer accesses the i variable in the immediately executed function, resulting in a closure.

thinking questions

You can think about the execution result of the following code and its reason, and judge whether there is a closure generated
1.

var name = 'this is window';
    var obj = {
        name: "this is  Obj",
        getNameFunc: function() {
            return function() {
                return this.name
            }
        }
    }
console.log(obj.getNameFunc()());     //this is window

Tip: When global variables are mounted in window , and the anonymous function this direction window

2.

var name = 'this is window';
var that;
    var obj = {
        name: "this is Obj",
        getNameFunc: function() {
            that = this;
            return function() {
                return that.name
            }
        }
    }
console.log(obj.getNameFunc()());     //this is Obj

Summarize:

  1. Closures are functions. A scope can access the local variables of another function, and the function where the accessed variable is located is the closure function.
  2. Closures extend variable scope
  3. In development, you should decide whether to use closures according to the actual situation

Tags: Javascript

Posted by qartis on Wed, 18 May 2022 17:19:58 +0300