The starting point
The reason for writing such platitudes in this article is to pave the way for the following design patterns. Now that I’ve started writing, I’m going to stick with it and keep writing. I’m sure there are a lot of people out there who are a little confused about closures, so let’s take a look
After all, the concepts of closures and higher-order functions are very component in development. So many advantages, so many advantages, so we’re going to stop beating around the busyways and jump right into today’s topic, closures and higher-order functions
closure
Closure is a topic that front-end ER cannot do without, and it is also a difficult and must understand concept. Closures are closely related to the scope and life cycle of variables. These two knowledge points we can not bypass, so understand together
Variable scope
First of all, there are two types of variable scope: global scope and local scope. The scope of a variable is also primarily the scope declared in a function
- When a variable is declared in a function without the var keyword, it is a global variable
- A variable declared in a function with the var keyword is a local variable, which can only be accessed within the function
function fn() { var a = 110; // a is the local variable console.log(a); // 110 } fn(); console.log(a); // a is not defined Indicates that internal variables cannot be accessed externallyCopy the code
The above code shows that the local variable a declared in a function is really not available outside the function. Small kind of son is also quite arrogant, for the challenges of the coder, but also do not believe that not a
Don’t worry, guest officer. Listen to the wind. Remember that in JS, functions are first-class citizens
A function can create a function scope. If you want to find a variable in a function scope, if the variable is not declared in the function, the search continues to the outer layer of the function, until you reach the global variable
So variables are searched from the inside out, which forms the so-called scope chain
var a = 7;
function outer() {
var b = 9;
function inner() { var c = 8; alert(b); alert(a); } inner(); alert(c); // c is not defined } outer(); // Call the functionCopy the code
Using the scope chain, let’s try to get to a, modify the FN function
function fn() { var a = 110; // a is local variablereturn function() { console.log(a); } console.log(a); // 110 } var fn2 = fn(); fn2(); / / 110Copy the code
So, so so, easy, small case, you can access from the outside to the local variable a
So here we have one of the meanings of closures: closures are functions that can read variables inside other functions. Ok, move on
Variable life cycle
Having solved the above problem of how to get the small a, let’s go over the concept of variable life cycle briefly.
- For a global variable, its life cycle is forever, unless we are unhappy and actively kill it.
- Local variables declared by var in a function are not so lucky. When the function is executed, local variables lose value and are discarded as garbage by the garbage collection mechanism
For example, code like the following is pathetic
function fn() { var a = 123; Console. log(a); } fn();Copy the code
Although the above garbage recycling process we can not see, but listening to sad tears ah. Can not be so cruel, I would like to pour all their, in exchange for your three lives three times.
Sadness comes, we can not refuse, then let us think of ways to change everything. Now let’s look at this code again:
function add() {
var a = 1;
return function() { a++; console.log(a); } } var fn = add(); fn(); // 2 fn(); // 3 fn(); / / 4Copy the code
The amazing thing about this code is that when the add function is finished, the local variable A is not destroyed, but still exists. What happens? Let’s break it down:
- When fn = add(), fn returns a reference to a function that contains the local variable a
- Since this local variable can still be accessed externally by fn(), there is no need to destroy it, so it is preserved
Closures are a nice thing to do, and they do a lot of work, including a classic online quiz
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script>
var aLi = document.getElementsByTagName('li');
for (var i = 0; i < aLi.length; i++) {
aLi[i].onclick = function() {
console.log(i); // ?
};
}
</script>
Copy the code
Raise your hand if you’ve seen this problem, it’s true that the whole point of this problem is to understand closures. The answer is 4 no matter what the answer is.
This is because the onclick event on the Li node is asynchronous. When click is triggered, the for loop completes as quickly as you can, and the value of variable I is already 4
So when li’s click event function starts looking for I from the inside out of the scope chain, it finds that I is already all 4
The solution is to use closures to store the I value for each loop. Then, when the click event continues down the scope chain, it finds the saved I first, so that each LI click can find the corresponding I value
<script>
var aLi = document.getElementsByTagName('li');
for (var i = 0; i < aLi.length; i++) {
(function(n) {// n is the corresponding index value aLi[I].onclick =function() { console.log(n); // 0, 1, 2, 3}; })(i); </script> </script> </script>Copy the code
Other role
Closures are widely used, and we’ll talk about some familiar ones. For example, they can encapsulate private variables. They can encapsulate variables that do not need to be exposed globally, so as to prevent global contamination of variables
var sum = (function() { var cache = {}; // Put the cache inside the function to avoid modification elsewherereturn function() {
var args = Array.prototype.join.call(arguments, ', ');
if (args in cache) {
return cache[args];
}
var a = 0;
for (var i = 0; i < arguments.length; i++) {
a += arguments[i];
}
return cache[args] = a;
}
})();
Copy the code
In addition, many of you have seen libraries like jQuery and underscore that have outermost layers of code that look like the following
(function(win, undefined) {
var a = 1;
var obj = {};
obj.fn = function() {}; Win.obj = obj; })(window);Copy the code
Yes, that’s right, modularity is possible with closures. You can also extend the use of variables, so let’s do another example
var monitor = (function() {
var imgs = [];
return function(src){
var img = new Image();
imgs.push(img);
img.src = src;
}
})();
monitor('http://dd.com/srp.gif');
Copy the code
The above code is used for the statistics case. In some previous browsers, the dots were lost because img was a local variable within a function and was destroyed when the function finished executing, possibly before the HTTP request was sent.
When this happens, wrap the IMG variable in a closure
Memory management
Many people have heard the version that closures cause memory leaks, so try to minimize the use of closures
Just Now is here to justify closures, not in the way you might think:
- Local variables are supposed to be destroyed as the function completes execution, but if the local variable is wrapped in the closure’s environment, the local variable will always exist. From the results of our above practice, there is nothing wrong with this
- But we use closures because we want to store variables for later use, which is consistent with the memory impact of putting them globally, so it’s not a memory leak. If you want to reclaim these variables in the future, just set the variables to NULL
- Also, it is easier to use closures with circular references, which can cause memory leaks if the closure’s chain of scope holds DOM nodes. But this is not a closure problem per se, nor is it a JS problem
- Blame old versions of IE for implementing a reference-counting strategy for garbage collection. In old IE, if a circular reference is made between two objects, then neither object can be reclaimed, but the memory leak caused by a circular reference is not the fault of the closure per se
- To solve the memory leak problem of the circular reference proxy, simply set the variable in the circular reference to NULL
The above is our justification for closures, closures are not easy to use, not to please. He knew it was not his pot, he did not need to carry it!
This is not the end
Although not the end, but still want to make a summative inflammation, otherwise how to live up to tonsil brother
Closure:
- Is a function that reads variables inside other functions, essentially parsing variables (inside out)
- Can be used to encapsulate private variables, modular implementation
- You can save variables to memory
So with closures out of the way, let’s take a minute to clear our heads.
However, the real reason is because the article content is too long, split into sister articles
So also invited the official to move, after a short rest, to continue to the next topic, higher-order functions