The concept of closures
In general, it can be summarized as follows: the inner function implements a reference to the external variable, and the external variable is stored for a long time. Generally speaking, a closure is actually a function that can access the internal variables of other functions. That is, a function defined inside a function, or you can just say that the closure is an embedded function.
A closure is a function that has access to variables in the scope of another function.
MDN: A combination of a function that is bound (or surrounded by) references to its surrounding state is a closure. That is, closures allow you to access the scope of an outer function within an inner function.
Execution context: (here we mainly talk about function execution context) each function has its own internal execution environment since its creation, and the execution of the statement, in each call will form its own execution context;
When a variable referenced internally does not exist, it looks up to its next level, and so forth, forming a chain of scopes
Here’s an example:
function fun1() {
var a = 1;
return function(){
console.log(a);
};
}
fun1();
var result = fun1();
result(); / / 1
Copy the code
From the above we can see that the inner function refers to a, forming a scope chain, which is essentially: there is a reference to the parent scope in the current environment
Some people might wonder: Does it have to return a function to qualify as a closure? The result, of course, is not a return to the concept of closures, as long as the inner function has a reference to the parent scope, as follows
var logNum;
function fun1() {
var num = 2
logNum = function() {
console.log(num);
}
}
fun1();
logNum();
Copy the code
In our code, the function is received as an external variable and executed externally, thus achieving the reference of the internal function to the parent scope
The use and presentation of closures
Many times we may have encountered an interview question like this
for(var i=0; i<5; i++){setTimeout(() = >{
console.log(i)
})
}
Copy the code
We know that the answer is five fives, so how do we answer this question to satisfy the other person? In fact, this problem can be around two points: scope and JS event even loop
SetTimeout is a macro task. In the JS single-threaded eventLoop mechanism, the macro task is executed only after the main thread completes the step task, so the callbacks in setTimeout are executed successively after the loop ends.
The setTimeout function is also a kind of closure, and its parent scope chain is window. Variable I is the global variable of window, and variable I is already 5 before setTimeout is executed, so the final output sequence is all 5.
How do we get him to print the 0,1,2,3,4 we want? We can modify it with anonymous self-executing functions as follows:
for(var i = 0; i <5; i++){ (function(num){
setTimeout(function timer(){
console.log(num)
}, 0)
})(i)
}
Copy the code
You can also use the block-level scope form introduced in ES6 to handle scope changes:
for(let i=0; i<5; i++){setTimeout(() = >{
console.log(i)
})
}
Copy the code
Or pass in the I as the third argument to the timer and print it as an argument to the callback
for(let i=0; i<5; i++){setTimeout(() = >{
console.log(i)
},0 , i)
}
Copy the code