closure
Think about a few questions
- What does scope mean in JavaScript?
- In what scenarios will closures be used?
- How does the timer loop output the increment of the number through JS code?
Scope introduction
Essentially, it refers to the scope that a variable can access; Before ES5, scopes were divided into two types: global scope and function scope. After ES6, block-level scope appeared
Global scope
In JS, a global variable is a variable that is mounted to the Window object, and can be accessed in any case
var globalName = 'global'; function getName() { console.log(globalName) // global var name = 'inner' console.log(name) // inner } getName(); console.log(name); // console.log(globalName); //global function setName(){ vName = 'setName'; } setName(); console.log(vName); // setName console.log(window.vname) // setName // globalName is a variable that can be accessed anywhere Variables do not have this abilityCopy the code
Advantages: It can be accessed anywhere
Disadvantages: naming conflicts
Function scope
A variable defined in a function is called a function variable, and it can only be accessed from inside the function, so its scope is called the function scope
function getName () { var name = 'inner'; console.log(name); //inner } getName(); console.log(name); // Name is defined in the getName function, so name is a local variable whose scope is in the getName function, also known as function scopeCopy the code
It is not accessible anywhere except inside the function itself. At the same time, the local variable is destroyed when the function is executed. So you can see that the name outside the getName function is not accessible
Block-level scope
ES6 has a new block-level scope, which is most directly expressed by the new LET keyword. Variables defined using the LET keyword can only be accessed in the block-level scope, which has the feature of “temporary dead zone”, that is, the variable cannot be used before the definition
If statement and for statement {… } this includes the block-level scope
Console. log(a) //a is not defined if(true){let a = '123'; The console. The log (a); // 123 } console.log(a) //a is not definedCopy the code
What is a closure?
A closure is simply a function that can access variables inside other functions
function fun1() { var a = 1; return function(){ console.log(a); }; } fun1(); var result = fun1(); result(); / / 1Copy the code
Why closures occur
When accessing a variable, the code interpreter first looks in the current scope. If it doesn’t find one, it looks in the parent scope until the variable is found or no parent scope exists. Such links are called scope chains.
var a = 1; function fun1() { var a = 2 function fun2() { var a = 3; console.log(a); / / 3}}Copy the code
The scope of the fun1 function points to the global scope (window) and itself; The scope of the fun2 function refers to the global scope (window), fun1, and itself; Scope is searched from the bottom up until the global scope Window is found, and an error is reported if the global scope is not present.
Essence: A reference to the parent scope exists in the current environment.
The representation of closures
Return a function
function fun1() {
var a = 1;
return function(){
console.log(a);
};
}
Copy the code
Whenever you use a callback function in timers, event listeners, Ajax requests, Web Workers, or any asynchrony, you’re actually using a closure
// timer setTimeout(function handler(){console.log('1'); }, 1000); $('#app').click(function(){console.log('Event Listener'); });Copy the code
Passed as a function parameter
var a = 1; function foo(){ var a = 2; function baz(){ console.log(a); } bar(baz); } function bar(fn){// this is the closure fn(); } foo(); // Print 2 instead of 1Copy the code
IIFE (execute the function immediately) creates a closure that holds the global scope (Window) and the scope of the current function, so it can output global variables
var a = 2; (function IIFE(){ console.log(a); })();Copy the code
How to solve the loop output problem?
for(var i = 1; i <= 5; I + +) {setTimeout (function () {the console. The log (I)}, 0)} / / 5,5,5,5,5Copy the code
The reason:
- SetTimeout is a macro task. Due to the single-threaded eventLoop mechanism in JS, macro tasks are executed after the simultaneous tasks of the main thread are completed, 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 6 before setTimeout is executed, so the final output sequence is all 6
So how do we output 1, 2, 3, 4, 5 in that order?
Using the IIFE
for(var i = 1; i <= 5; I ++){(function(j){setTimeout(function timer(){console.log(j)}, 0)})(I)} // 1, 2, 3, 4, 5Copy the code
Use let in ES6
The new let definition of variables in ES6 has revolutionized JS since ES6, giving JS block-level scope, where code is scoped on a block-level basis. With the modified code, you can achieve the desired results above.
for(let i = 1; i <= 5; i++){ setTimeout(function() { console.log(i); }}, 0)Copy the code
The timer passes a third argument
for(var i=1; i<=5; i++){ setTimeout(function(j) { console.log(j) }, 0, i) }Copy the code
\