Reading Contents
- What is a closure?
- Closure features
- The function of closure:
- Code example for closure
- Things to note
- Summarize
Closures are a relatively important concept in JavaScript and are also a technology that is used more frequently in daily work. Let's give a small summary of it
What is a closure?
Official statement:
A closure is a function that has permission to access variables in another function scope. The common way to create closures is to create another function inside one function and access local variables of this function through another function-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Here is a simple closure:
function A(){ var text="hello world"; function B(){ (text); } return B; } var c=A(); c(); // hello world
According to the literal meaning, function B has the right to access the variable (text) in the scope of function A, and access the local variable text of this function through another function C. Therefore, function B forms a closure. It can also be said that C is a closure because what C does is actually executing is function B.
It should be noted that directly executing A(); will not react. Because return B is not executed unless it is return B();
Closure features
Closures have three characteristics:
1. Function nested functions
2. External parameters and variables can be referenced inside the function
3. Parameters and variables will not be collected by the garbage collection mechanism
Let me explain the third point, why are the parameters and variables of the closure not collected by the garbage collection mechanism?
First, let's learn about it firstThe principle of garbage collection in javascript:
(1) In javascript, if an object is no longer referenced, then the object will be recycled by GC (garbage collection);
(2) If two objects refer to each other and are no longer referenced by the third person, then these two objects refer to each other will also be recycled.
In the above example code, A is the parent function of B, and B is assigned to a global variable C (the life cycle of the global variable will not end until the browser uninstalls the page), which causes B to always be in memory, and B's existence depends on A, so A is always in memory and will not be recycled by the garbage collection mechanism after the call is finished.
The function of closure:
In fact, the function of closures is also determined by the characteristics of closures. According to the above closure characteristics, the function of closures is as follows:
1. You can read variables inside the function instead of defining global variables together to avoid polluting the environment.
2. Keep the values of these variables in memory at all times.
Code example for closure
The following mainly introduces several common closures and analyzes them:
demo1 The accumulation of local variables.
function countFn(){ var count=1; return function(){ // Function nested functions count++; (count); } } var y = countFn(); //The external function is assigned to the variable y;y(); //2 //The y function is called once, and the result is 2, which is equivalent to countFn()()()y(); //3 //The y function is called the second time, and the result is 3. Because the count of the last call is still stored in memory and has not been destroyed, the accumulation is achievedy=null; //Garbage collection, freeing memoryy(); // y is not a function
Since the first execution is completed, the variable count is still stored in memory, so it will not be recycled, so that the last value can be accumulated during the second execution. When y=null is introduced, the reference is destroyed and the memory is released
Use closures in demo2 loop
The code is as follows (three code examples below): Our purpose is to call the loop sequence number in each loop:
demo2-1
for (var i = 0; i < 10; i++) { var a = function(){ (i) } a() //The order is 0--9}
The result of this example is not questionable, we print out 0-9 in turn
Each layer of anonymous function and variable i form a closure, but there is no problem in the loop, because the function is executed immediately in the loop body.
demo2-2
But it's different in setTimeout
for(var i = 0; i < 10; i++) { setTimeout(function() { (i); //10 times 10 }, 1000); }
What we expect is to print out 0-10, and the actual situation is to print out 10 times 10. Even if the time of setTimeout is changed to 0, 10 10 are printed. Why is this?
This is because of a mechanism of setTimeout, setTimeout is fromThe task queue starts to be timed at the end. If there is a previous process that has not ended, it will wait until it ends before starting to time.Here, the task queue is its own loop.
The timer starts when the loop ends, so no matter what, the i in the setTimeout is the last loop i. In this code, the last i is 10, so 10 10 are printed.
This is why the callback of setTimeout is not the value of the loop, but the last value
demo2-3
Solve the problem that setTimeout above cannot print out loops in sequence
for(var i=0;i<10;i++){ var a=function(e){ return function(){ (e); //Enter 0--9 in turn } } setTimeout(a(i),0); }
Because the first parameter of setTimeout requires a function, return a function to it, and pass i as a parameter in the return, and cache i through the formal parameter e, which means that the e variable is equivalent to a copy of i and brought into the returned function.
When setTimeout is executed, it has a reference to e, and this value will not be changed by the loop.
You can also use the following writing method, similar to the above:
for(var i = 0; i < 10; i++) { (function(e) { setTimeout(function() { (e); //Print out 0-9 in turn }, 0); })(i); }
Add events in demo3 loop
Look at a typical demo below.
We hope that every time we click on Li, we will alert the index value of Li, so use the following code:
<ul > <li>The first</li> <li>The second one</li> <li>Third</li> <li>The fourth</li> </ul> var nodes = ("li"); for(i = 0,len=;i<len;i++){ nodes[i].onclick = function(){ alert(i); //The values are all 4 }; }
Things went against my expectations. No matter which li clicked, it is alert(4), which means it is index value after the alert loop ends. Why is this?
This is because the loop binds events for different elements. If a variable related to the loop is called in the event callback function, the variable takes the last value of the loop.
Since the bound callback function is an anonymous function, in the above code, this anonymous function is a closure and the scope is the outer scope (that is, the scope in for). When the event is triggered, the variables in the scope have already gone to the end with the loop.
Another point is that events need to be triggered, and in most cases, the loop has ended when it is triggered, so the loop-related variables are the last value.
To realize the index value of li and alert, the above code needs to be modified as follows:
<ul > <li>The first</li> <li>The second one</li> <li>Third</li> <li>The fourth</li> </ul> var nodes=("li"); for(var i=0;i<;i++){ (function(e){ nodes[i].onclick=function(){ alert(e); }; })(i) }
Solution: Add several corresponding closure domain spaces (anonymous functions are used here), which are specifically used to store the content that originally needs to be referenced (subscript).
When the function is executed immediately, the e value will not be destroyed because there is an anonymous function in it (it can also be said that the variable will not be destroyed because of the existence of the closure). After execution, the connection between the e value and the global variable i is cut off.
That is to say, when executing, the amount of i passed in, and the e that executes the function immediately is, but the value of e will not disappear because of the existence of anonymous functions.
The following solution can also be used, the principle is the same:
<ul > <li>The first</li> <li>The second one</li> <li>Third</li> <li>The fourth</li> </ul> var nodes=('li'); for(var i = 0; i<;i++){ (function(){ var temp = i; nodes[i].onclick = function () { alert(temp); } })(); }
Things to note
1. Cause memory leaks
Since the closure carries the scope of the function that contains it, it consumes more memory than other functions. Overuse of closures can lead to excessive memory usage, so only consider using closures if absolutely necessary.
2. Using this in closures may also cause some problems.
Code example: From "JS Advanced Programming 3";
In fact, our goal is to alert the name in the object.
var name="The Window"; var object={ name:"My Object", getNameFunc:function(){ return function(){ return ; } } } alert(()()); // The Window
Because in a global function, this is equal to window, and when the function is called as a method of an object, this is equal to that object. However, the execution environment of anonymous functions is global, so its this object usually points to the window.
When each function is called, two special variables will be automatically taken: this and arguments. When an internal function searches for these two variables, it will only search until its active object. That is to say, the return function inside will only search
When this is global, stop searching. Because it can never directly access these two variables in external functions.
Make a slight modification to save this object in the external scope in a variable that can be accessed by a closure. This allows the closure to access the object.
var name="The Window"; var object={ name:"My Object", getNameFunc:function(){ var that=this; return function(){ return ; } } } alert(()()); // My Object
We assign this object to that variable. This variable can also be accessed by the closure after it has been defined. Therefore, even after the function returns, that still refers to this object, so calling()() returns "My Object".
Summarize
When other functions are defined inside the function, a closure is created. The closure has permission to access all variables contained within the function.
The scope of a closure contains its own scope, the scope of the function, and the global scope.
When a function returns a closure, the scope of the function will be saved in memory until the closure does not exist.
Use of closures must maintain additional scopes, and all overuse of them can take up a lot of memory
The above is all the content of this article. I hope that the content of this article will help you study or work. I also hope to support me more!