JavaScript scope closure (JavaScript you Don't know)
JavaScript closure is a deep understanding of JavaScript development engineers. In March, I wrote my blog "JavaScript closure", which briefly described the working process of the closure and provided several examples. I didn't figure it out!
Now with a more in-depth understanding of JavaScript, I have just read 《
JavaScript that you don't know (volume-up)This book, so I took the opportunity to sort it out and plan it from the bottom layer and principles.
JavaScript does not have dynamic scopes. It only has lexical scopes. The Lexical scope is determined during code writing or definition, while the dynamic scope is determined at runtime. Before learning about closures, we first need to know what the lexical scope is (the scope is determined by the position of the function declaration when code is written ).
I. What is closure Example 1:
function foo(){var a = 2;function bar(){console.log(a);}return bar;}var baz = foo();bzz(); //2
After foo () is executed, it is generally considered that the garbage collection mechanism will destroy the entire internal scope of foo (), and the closure can prevent such a thing from happening, so that its internal scope still exists. Because bar () is inside foo (), it has a closure that covers the foo () scope, so that this scope can survive for reference by bar () at any time later.
Bar () still holds a reference to this scope, and this reference is called
Closure.
In short: When a function can remember and access its lexical scope, a closure is generated even if the function is executed outside the current lexical scope.
Example 2: No matter which method is used to pass the value of the function type, the closure can be observed when the function is called elsewhere.
Function foo () {var a = 2; function baz () {console. log (a);} bar (baz);} function bar (fn) {fn (); // This is the closure}
Example 3: pass an internal function (timer) to setTimeout. Timer has a closure that covers wait () scopes and has reference to the variable message.
After wait () is executed for 1000 milliseconds, its scope does not disappear, and timer still maintains the closure of the wait () scope.
function wait(message){setTimeout( function timer(){console.log(message);},1000);}wait(Hello,ligang);
Example 4: The following activator () has a closure that covers the setupBot () scope!
function setupBot(name, selector){$(selector).click(function activator(){console.log(Activating: + name);});}setupBot(Closure Bot 1, #bot_1);setupBot(Closure Bot 2, #bot_2);
Ii. loops and closures
For (var I = 1; I <= 5; I ++) {setTimeout (function timer () {console. log (I) ;}, I * 1000);} // expected: 1 ~ 5 // result: the frequency output every second is 5 times. 6
First explain: "I * 1000", the five scheduled tasks are executed after 1 s, 2 s, 3 s, 4 s, and 5 s, respectively, not 1 s, 3 s, 6 s, 10 s, 15 s. That is, the frequency is 1 s, not 1 s for each interval. If I is removed and written as "1000", 6 is output five times after the for statement is executed for 1 s.
The callback function is executed only after the loop ends. Therefore, the I value is output as the condition for loop termination. In fact, when the timer runs, even if setTimeout (..., 0) is executed in each iteration, all callback functions are still executed after the loop ends.
According to the working principle of the scope, although the five functions are defined separately in each iteration, they are all enclosed in a shared global scope, so there is actually only one I.
Solution 1:
For (var I = 0; I <= 5; I ++) {(function (j) {setTimeout (function timer () {console. log (j) ;}, j * 1000) ;}) (I) ;}// result: 1 ~ is output every second ~ 5
Each iteration generates a new scope, so that the callback of the latency function can close the new function within each iteration. Each iteration contains a variable with the correct value for our access.
Solution 2 (ES6 ):
For (var I = 0; I <= 5; I ++) {let j = I; setTimeout (function timer () {console. log (j) ;}, j * 1000);} // result: 1 ~ 5
For (let I = 0; I <= 5; I ++) {setTimeout (function timer () {console. log (I) ;}, I * 1000);} // result: the frequency output once per second is 5 times.
Iii. Modules
The module must have two necessary conditions:
(1) There must be an external closed function, which must be called at least once (a new module instance will be created each time ).
(2) The closed function must return at least one internal function so that the internal function can form a closure in the private scope and can access or modify the private State.
Typical modularization:
Function CoolMoudle () {var something = cool; var doSomething = function () {console. log (something) ;}return {doSomething: doSomething };}var foo = CoolMoudle (); // if the external function CoolMoudle () is not executed (), neither the internal scope nor the closure can create foo. doSomething (); // cool
Singleton mode:
Var foo = (function CoolModule (id) {function change () {// modify public APIpublicAPI. identify = identify2;} function identify1 () {console. log (id);} function identify2 () {console. log (id. toUpperCase ();} var publicAPI = {change: change, identify: identify1}; return publicAPI;}) (foo module); foo. identify (); // foo modulefoo. change (); foo. identify (); // FOO MODULE