closure
Problems caused by closures
Scope and scope chain
Variables in JS are not used everywhere. The scope of a variable is the scope of the variable. Scope is divided into global scope and local scope,
function fn1() { let a = 1; } fucntion fn2 () { let b = 2; } In the two declared functions, fn1 and fn2 create two private scopes, that is, a and b can only be used in fn1 and fn2.Copy the code
Each function has its own scope. When a variable or function needs to be found, the local scope is searched to the global scope. Such a set of scopes is called the scope chain.
var a = 1 function fn1 (){ function fn2(){ function fn3(){ var a = 3; console.log(a); } // execute fn2 fn2 (); } // execute fn1 fn1(); } // execute the function fn (); This function, executed from fn3 to fn1, is a local-to-global look-up. All the way up to finding a is using the scope chainCopy the code
Execution context and execution stack
Execution context is the abstract concept of the context in which JS code is parsed and executed. There are three types of execution contexts: global execution context: the default underlying execution context in which all code in a function is parsed and executed. Creates a global Window object. There is only one global execution context in a program. 2. Point this to a global object. Function execution context: Every time a function is called, a function execution context is created. Each function has its own execution context, which is created only when the function is called. When the function is completed, the execution context is destroyed immediately. Eval Execution Context Function code in EVAL also creates an execution context, which is less commonly used.
Execution stack The execution stack is the call stack, a LIFO (lifO) data structure that stores all execution contexts created while the code is running
When the JS engine encounters a script for the first time, it creates a global execution context and pushes it onto the current execution stack. Each time the engine encounters a function call, it creates a new execution context at the top of the stack for that function. When the function completes, the execution context exits from the stack and continues to execute the next context in the stack.
Conclusion 1. The reason why a variable in a function cannot be referenced outside the function is that it is a private occupied memory formed in the memory and cannot be referenced outside the function. 2. The stage of executing the code is (AO stage) – JS compilation process 3. The reason why the function is not executed when it is created. 4 The value of the reference type is too large. Stack memory does not fit, can only be stored in heap memory
Now comes the blockbuster closure
Third, the closure
Function execution, forming a private execution context, protect the inside of the private variables from outside interference, in addition to protecting the private variables, but also save some content, this mode is called closure
function fn(){
var name = 'zhangsan';
function displayName(){
alert (name);
}
var myfn displayName;
}
var myfn = makefn()
myfn();
Copy the code
The function of closures
1, when team development, each developer put their own code in a private scope, to prevent the variable name conflict between each other, the need to provide others with methods, by return or window.xxx way exposed to the global. 2. Jquery source code also uses this protection mechanism. 3. Encapsulate private variables
Anonymous execution function
(function (a) {console.log(a)}) (3) //3Copy the code
Anonymous execution functions are executed only once and destroyed immediately after execution. External variables cannot be referenced internally and will be released after execution. This mechanism does not pollute global objects
The cache
var CachedSearchBox = (function(){ var cache = {}, count = []; Return {attachSearchBox: function(dSID){if(dsid in cache){attachSearchBox: function(dSID in cache){return cache[dsid]; } var FSB = new uikit.webCtrl. SearchBox(dsid); // Create cache[dsid] = FSB; If (count.length > 100){delete cache[count.shift()]; } return fsb; }, clearSearchBox : function(dsid){ if(dsid in cache){ cache[dsid].clearSelection(); }}}; }) (); CachedSearchBox.attachSearchBox("input1");Copy the code
When you call an object repeatedly, you can use the closure feature to call the object from the cache instead of creating a new object.
Implement encapsulation
Var person = function(){var name = "default"; return { getName : function(){ return name; }, setName : function(newName){ name = newName; }}} (); console.log(person.name); // Use undefined console.log(person.getName()); // default person.setName("Tom"); console.log(person.getName()); // TomCopy the code
Internal variables cannot be accessed outside of Person or through the interface provided by the closure
To realize the object in object oriented, the traditional object language provides the template mechanism of the class
function Person(){ var name = "default"; return { getName : function(){ return name; }, setName : function(newName){ name = newName; }}}; var john = Person(); console.log(john.getName()); // default john.setName("john"); console.log(john.getName()); // john var jack = Person(); console.log(jack.getName()); // default jack.setName("jack"); console.log(jack.getName()); // jackCopy the code
Both John and Jack can be called instances of the Person class because they have independent access to the name member.
This I understand is not very good so use the way of reprinting
Closures have three features: 1. Functions nested functions. 3. Arguments and variables are not collected by the garbage collection mechanism
The application of closures
var num = 10; var obj = {num; 20}; obj.fn = (function (num) { this.num = num * 3; num ++ ; return function (n) { this.num += n ; num ++; console.log (num); } }) (obj.num) var fn = obj.fn; fn(5) obj.fn(10) console.log(num,obj.num) //22 23 65 30Copy the code
1. Declare a global scope (window) 2. Step 1: promote variables under the global scope (note: function expression, arrow function, immediately execute function does not promote variables) 3. 4. Normal (number, string) variables or constants are assigned directly
If an object or function assignment is encountered, a space is created in the heap to store the string in. . Store property name. Assign an address to a variable. If a self-executing function is encountered, the return of the self-executing function is assigned to the variable. . The function executes, declaring a private scope (variables are private). . Function parameter assignment. . Variable promotion. . Self-executing function code continues execution from top to bottom. . If the self-executing function has no body, this points to the window; Note: see if the value changed is a private variable or some other variable. . If a self-executing function returns a function (return). . Create a heap memory space (to store strings); . Returns the address of the heap memory to return. So the address of the variable returned by the execution of the self-executing function points to the address of the return. . In this case, the function inside the function is referred to by the external variable, so the private scope is not destroyed. Encountered function execution. . The function executes, forming a private scope (variables are private). . Parameter assignment. . Variable promotion. . Functions are executed from the top down. . The reference to this follows three principles, as well as the scope of private scoped variables. After the function completes, scope destruction is performed
Problems caused by closures and solutions
A common problem with closures is that they can cause memory leaks. Since JS closures store function variables in memory, they can cause memory leaks. SetTimeout setTimeout essentially delays code execution until a specified time, after the current script synchronization task or queue event processing is complete, Is executed within a specified period of time, not immediately
Solutions:
for (var i = 0; i < 5 ,i ++) { setTimeout(function () { console.log(i); }); } for (var I = 0, I < 5; Function (num) {setTimeout(function () {console.log(num); },num*1000); Create a closure inside setTimeout and pass it as a parameter for (var I = 0; i<5; I++){ setTimeout (function (num){ return function () { consoe.log(num); } }(i),I*1000); }Copy the code