The original intention of writing this series of articles is to "let every front-end engineer master high-frequency knowledge points to help work." This is the 13th cut of the front-end Baiti cut. I hope that friends will pay attention to the official account "Kite Holder" and arm their minds with knowledge.
13.1 Definition
In JavaScript, according to the rules of lexical scope, internal functions can always access the variables declared by their external functions. When an internal function is returned by calling an external function, even if the external function has been executed, the internal function refers to the external The variables of the function are still stored in memory, so the collection of these variables is called a closure.
13.2 Closure implementation
Nest a function in another function or pass an anonymous function as a value to another function.
// 函数fun1中嵌套了fun2,fun2作为参数返回,次吃调用时仍能打印val1,构成闭包
function fun1() {
const val1 = 10;
function fun2() {
console.log(val1);
}
return fun2;
}
function fun3() {
const val2 = 20;
// 定时器中的为一个匿名函数,其作为参数传入了,函数fun3执行完毕之后,1s钟后才会执行定时器函数,但此时还能打印val2,构成闭包
setTimeout(function() {
console.log(val2);
}, 1000);
}
13.3 Process
Take a look at the entire execution flow of the closure according to the following function
function main() {
const val1 = 20;
var val2 = 2
function valResult() {
return val1 * val2;
}
return valResult;
}
var result = main();
console.log(result()); // 40
The above figure shows the call stacks of various periods, and the following points need to be paid attention to:
- When the main function is executed, the execution context of the main function is popped from the top of the stack;
- The returned method (valResult) calls the val1 and val2 variables in the main function, and these two variables will be packaged into a closure closure and added to [[scopes]];
- When calling the returned method, the scope chain is: result function scope-Closure (main)-global scope
13.4 Advantages and disadvantages
advantage
(1) Variables can be reused and will not cause variable pollution;
(2) Can be used to define private attributes and private methods
Disadvantage
(1) A context that is not destroyed will be generated, resulting in excessive stack/heap memory consumption
(2) It will cause memory leaks.
Extension: How are closures recycled?
- If the function introduced by the closure is a global variable, the closure will always exist until the page is closed; but if the closure is no longer used in the future, it will cause a memory leak;
- If the function that refers to the closure is a local variable, after the function is destroyed, the next time the JavaScript engine performs garbage collection, it is judged that the content of the closure is no longer used, and the garbage collector of the js engine will collect it.
13.5 Purpose
There are two main uses of closures:
- Create private variables
function MyName(name) {
return {
getName() {
return name;
}
}
}
const myName = MyName('lili');
// 只能通过getName访问对应的名字,别的方式访问不到
console.log(myName.getName()); // lili
- As a callback function. When a function is passed as a value somewhere, and a callback is made at some point, a closure is created. For example, timers, DOM event listeners, Ajax requests.
function fun(name) {
setTimeout(() => {
console.log(name);
}, 1000);
}
fun('linlin');
13.6 Classic Closure Problem
The [[scope]] of multiple child functions all point to the parent at the same time, which is completely shared. Therefore, when the parent's variable object is modified, all child functions are affected.
for (var i = 1; i < 5; i++) {
setTimeout(() => console.log(i), 1000);
}
The above code is intended to output 1, 2, 3, 4, but the result is four 5s. In order to solve this problem, there are three main methods.
- Variables can be passed in in the form of , avoid using the default [[scope]] search upward
for (var i = 1; i < 5; i++) {
(function(i) {
setTimeout(() => console.log(i), 1000);
})(i);
}
- Use the setTimeout package and pass in the third parameter. (Note: There can be multiple parameters after setTimeout, starting from the third parameter, it is used as an additional parameter of the return function)
for (var i = 1; i < 5; i++) {
setTimeout(value => console.log(value), 1000, i);
}
- Use block-level scope to make variables an attribute of their own context and avoid sharing
for (let i = 1; i < 5; i++) {
setTimeout(() => console.log(i), 1000);
}
1. If you think this article is good, share it, like it, and let more people see it
2. Follow the official account holders, and kill the front-end 100 questions with the account owner.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。