The original intention of this series of articles is to “let each front-end engineer master the high frequency knowledge, for the work of power”. This is the front end of the 13th cut, I hope friends pay attention to the public number “kite”, armed with knowledge of their minds.
13.1 define
In JavaScript, according to the rules of lexical scope, internal function can always access the external variables function declarations, as by calling an external function returns after an internal function, even if the end of the external function have been executed, but the variables of internal function refer to external function is still kept in memory, the collection of these variables is called closure.
13.2 Closure implementation
Nesting another function in one function or passing an anonymous function as a value in another function.
// The function fun1 is nested with fun2, and fun2 is returned as a parameter. The next call can still print val1, which forms the closure
function fun1() {
const val1 = 10;
function fun2() {
console.log(val1);
}
return fun2;
}
function fun3() {
const val2 = 20;
// The timer is an anonymous function, which is passed in as an argument. After fun3 is executed, the timer function will be executed 1s later, but val2 can also be printed to form the closure
setTimeout(function() {
console.log(val2);
}, 1000);
}
Copy the code
13.3 process
Take a look at the closure execution flow through the following functions
function main() {
const val1 = 20;
var val2 = 2
function valResult() {
return val1 * val2;
}
return valResult;
}
var result = main();
console.log(result()); / / 40
Copy the code
The figure above shows the call stack for each period, with the following points to focus on:
- When main completes, the execution context of main pops up from the top of the stack.
- The returned valResult calls the variables val1 and val2 in the main function. These variables are packaged as closure and added to the [[scopes]] function.
- When calling the returned method, the scope chain is: Result function scope — Closure (main) — global scope
13.4 the advantages and disadvantages
-
advantages
(1) Variables can be reused without causing variable pollution;
(2) Can be used to define private properties and private methods
-
disadvantages
(1) Undestructible context will be generated, resulting in excessive stack/heap memory consumption
(2) It will cause memory leakage.
Extension: How are closures recycled?
- If the function introduced by the closure is a global variable, the closure will exist until the page closes; But if this closure is not used in the future, it can cause a memory leak;
- If the function that refers to a closure is a local variable, and the function is destroyed, the next time the JavaScript engine performs garbage collection, the js engine’s garbage collector determines that the closure content is no longer in use, then the js engine’s garbage collector will collect it.
13.5 use
There are two main uses for closures:
- Creating private variables
function MyName(name) {
return {
getName() {
returnname; }}}const myName = MyName('lili');
// Only getName can access the corresponding name
console.log(myName.getName()); // lili
Copy the code
- As a callback function. A closure is created when a function is passed somewhere as a value and called back at some point. Examples are timers, DOM event listeners, and Ajax requests.
function fun(name) {
setTimeout(() = > {
console.log(name);
}, 1000);
}
fun('linlin');
Copy the code
13.6 The classic closure problem
The [[scope]] of multiple subfunctions all point to the parent at the same time and are fully shared. So when the parent variable object is modified, all child functions are affected.
for (var i = 1; i < 5; i++) {
setTimeout(() = > console.log(i), 1000);
}
Copy the code
The code above is supposed to print 1, 2, 3, 4, but it turns out to be four 5’s. There are three main ways to solve this problem.
- Variables can be passed in as function arguments, avoiding the default [[scope]] look-up
for (var i = 1; i < 5; i++) {
(function(i) {
setTimeout(() = > console.log(i), 1000);
})(i);
}
Copy the code
- Use the setTimeout wrap, passed in as the third argument. (Note: setTimeout can be followed by multiple arguments, starting with the third argument, which is used as an additional argument to the callback function.)
for (var i = 1; i < 5; i++) {
setTimeout(value= > console.log(value), 1000, i);
}
Copy the code
- Use block-level scopes to make variables properties of their own context and avoid sharing
for (let i = 1; i < 5; i++) {
setTimeout(() = > console.log(i), 1000);
}
Copy the code
1. If you think this article is good, share and like it so that more people can see it
2. Pay attention to the public number of kite, and the number of the Lord together to kill the front hundred.