In the process of front-end learning, we will inevitably encounter many problems, so today we will talk about two questions from a beginner's perspective:
What is a closure?
What are the functions of closures?
In fact, closures are everywhere when we learn JavaScript, you just need to be able to recognize and accept it. Closures are not a tool that requires learning a new syntax or pattern to use. Closures are a natural consequence of writing code based on lexical scope. We rarely need to intentionally create closures when writing code.
I believe that many friends are already muttering in their hearts at this time, what is this lexical scope? Don’t panic, just listen to me slowly. In short, lexical scope is the scope defined in the lexical stage. In other words, lexical scope is determined by where you place variables and block-level scopes when you write your code, so the scope remains unchanged when the lexical analyzer processes the code (most of the time) . ——"JavaScript You Don't Know"
Let's take an example first:
function test(){ var arr = [] for(var i=0;i<10;i++){ arr[i]=function(){ console.log(i); } } return arr } var myArr = test() // myArr[0]() // myArr[1]() // ... for(var j = 0; j < 10; j++){ myArr[j]() } //In order to avoid tediousness, a second loop is used here to call the function in the first loop in the test function and print out ten results.
Let's analyze this code first: When this code is executed, according to common sense, it should be analyzed It prints out ten numbers from 0 to 9 in sequence; but the for loop does not take time to run (neglected in microseconds). When the function test returns arr, there are 10 function(){console. log(i);}, the function in the array is not executed at this time. When var myArr = test() calls the test function, since the execution time of the for loop is ignored, i is already 10 at this time, so what is printed is 10 out of 10.
I believe someone will ask at this time, what does this have to do with the closure we are going to talk about? So if we slightly modify this code and change it into an accumulator, how can we implement it?
I believe there will be big shots at this time who will say, isn’t that simple?
Change the var definition to a let definition so that the first for loop becomes a block-level scope, then it can become an accumulator. Of course there is no problem,
but what we are talking about today is how to implement an accumulator in ES5. Then let’s take a look at the following code:
function test(){ var arr = [] for(var i=0;i<10;i++){ (function(j){ arr[j]=function(){ console.log(j); } })(i) } return arr } var myArr = test() for(var j = 0; j < 10; j++){ myArr[j]() }
Careful friends will definitely find that this is to change the function body in the loop into a self-executing function, but the output result at this time is to output ten numbers from 0 to 9 in sequence, and this includes the closure Package, when we start executing this code, the second for loop will be called ten times. When each self-executing function is executed, an AO object of the self-executing function will be created. There is an AO object in this self-executing function. The attribute name is j. Normally, after the execution function is executed, its AO object should be destroyed. However, when myarr[j] () is executed, the AO object of arr[j] at the top of the scope chain is now I looked for the attribute name j, but I didn't find it. I searched down the scope chain and found it in the AO object of the self-executing function. Therefore, when the self-executing function ends, its AO object will not be recycled by the garbage collection mechanism. , otherwise an error will be reported when myarr[j] () is executed, and a closure will be formed.
Let's take another example
function a(){ function b(){ var bbb = 234 console.log(aaa); } var aaa = 123 return b // b was born in a, but was saved} varglob = 100 var demo = a()We first use pre-compilation to analyze the code of
demo()
. First, define a global GO object. Look for the global declaration and find the global variable declaration. The variable declaration will be used as the attribute name of GO. The value is undefined. Find it in the global declaration. For function declaration, the function name is used as the attribute name of the GO object, and the value is assigned to the function body. At this time it should be GO{ glob: undefined--->100; demo: undefined; a: fa(){} }; Then create an AO{ aaa: undefined--->123;b: fb() for function a {} }, and finally precompile function b in function a to create an AO of b { b: undefined--->234}; at this time, the order of the scope chain is 1. AO object of function b; 2. AO object of function a; 3. Global GO object. When we print aaa in function b, we start from the top of the scope chain. If there is no aaa in the AO object of function b, we will search down along the scope chain to find the AO of the second-level function a. The object is to find the value of aaa as 123 and output the result.
If we did not analyze it from the perspective of precompilation, we would think that aaa should report an error at this time. When var demo = a() is executed, when the execution of the a function ends, then the AO object corresponding to a should be destroyed. According to Common sense analysis: When we execute the demo, the scope chain should create the AO object and GO object of b. At this time, there is only the AO object of b and no AO object of a. The value of aaa should not be printed out, but at this time, the value of aaa The value is 123, which means that the AO object of a has not been destroyed, so why? The reason is that a closure is created here. When the execution of var demo = a() is completed, the garbage collection mechanism will ask, Brother a function, I think you have finished executing it. Can your running memory be released to me? , but at this time function a could only shake his head helplessly and said, Brother, I am not sure whether I have completed the execution. After I executed it, I created a b, but b is not under my control, so I am not sure whether b. was called, so I'm not sure if I have completed the execution. The garbage collection mechanism thought about it. Since you don't know, I won't recycle it. If I recycle the unfinished ones, I should report an error, so at this time a The AO object is not recycled.
I believe that through these two examples, you already have a general understanding of closures. Next, let’s talk about the functions of closures.
The function of closure is
- can
- to implement public variables. For example: accumulator (3.js)
- be cached
- to achieve encapsulation, privatization
- and modular development of attributes to prevent contamination of global variables.
Let’s also give an example of the function of closure (3.js).
var count = 0 function add() { return count++ } console.log(add()); console.log(add()); console.log(add());
This is a relatively common accumulation code, but if during our internship or even at work, the company requires you to encapsulate the accumulator into a modular code, then at this time, for the sake of the module We try to avoid defining global variables as much as possible, but how can we achieve it without defining global variables? At this time we can use closures;
function add() { var count = 0 function a() { ++count console.log(count); } return a } var res = add() res() res() //After the add function ends, the AO object of add is not destroyed, because after the add function is executed, the returned a forms a closure without knowing whether it has been called, so that it can be encapsulated into a module without using global variables. ized accumulator.
So these are some of my personal opinions on closures and their functions. At present, I only have a superficial understanding of closures. After subsequent study and improvement, there will be subsequent articles about closures. Thank you for watching. Welcome. Criticize and correct, and make progress together.