The indentation of the following code snippet is not complete yet. You can download pdf to read it.
Contents
- Summary
- What is closure?
- Execution space (Execution Context, Execution Context)
- Closure usage
- Closure Efficiency
- Application suggestions
- Conclusion
- References
- Rst source code in this article
What is closure?
One definition is:
A "closure" is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression ).
My understanding is:ClosureIs an expression (usually a function), which corresponds toEnvironmentShared with some free variables, and thisEnvironmentThenBindWith those free variables (orEndThis expression is also calledClosure). The so-calledEnvironmentIs a larger block. All free variables are declared (meaningful) in this block.BindThat is, the scope of these free variables is the environment.
Here is a simple example.
VarFlag= False; // Debug Switch // Env is the so-called Environment // Inner is the so-called expression, and name is the so-called free variable FunctionEnv ()// The entire env can be regarded as a closure{VarName= "Zhutao"; FunctionInner (){ReturnName+ "Is a student .";}ReturnInner; // An internal function is returned.}// Closure endsFlag= True; If(Flag ){// This is the most amazing place. When code is executed here, the inner function actually has an env body, // But it can still be referenced. This is called closure. VarInner_func_ref=Env ();// At this time, inner_func_ref references the inner () function object.Alert (inner_func_ref ());// Zhutao is a student.}
In the above example, the function env is definedEnvironmentThe inner of the function is the so-calledExpressionAnd name is the so-calledFree variable,BindIn envEnvironmentThe end of. env is the end of closure.
In javascript, if the internal function has its own external function body that can still be referenced, the so-called closure will be formed.
Before learning about closure, we need to know some other knowledge.
Execution space (Execution Context, Execution Context)
In javascript, each line of executable code has a certainExecution SpaceSuch as Global execution space, function execution space, and recursive function execution space. A complete javascript Execution Process can be considered asExecution space Stack, ConstantlyExecution Space(Out stack, into Stack ).
This is a very important concept. The understanding of this concept is another article to be completed in this series.This keywordThe understanding is also closely related.
For more information, see the upcomingThis keyword.
The execution space can be understood as an object set with attributes, but these attributes are generally not accessible at will, and these object sets provide a certain context (Space) for code execution ).
When a function is executed, the execution space of the function will be created (so-called stack entry). The execution is complete, then the execution space exits and returns to the original execution space (the so-called out-of-stack), while the js interpreter maintains suchExecution space StackTo provide different execution spaces for different codes.
So what is the relationship between the execution space and closure?
To put it simply, a certain execution space corresponds to a certain closure. Only the method located in the same closure can access the variables of the same closure.
A simple example:
// Context exampleFlag= True; VarTmpobj={Name: "Zhutao",Func: Function(){Return "Call by func" + This. Name;}};If(Flag ){// When the code is executed here, the context is still global.Alert (tmpobj. name); alert (tmpobj. func ());// Enter the context of func // Return to the global context}
Closure usage
When internal functions and free variables are in the same closure, they can be accessed at will, but the Declaration Order is not important.
Several common examples:
// Some applicationsFlag= True; FunctionOuterFun (){VarNum= 100; VarPrintNum= Function() {Alert (num );}// The num referenced here is a reference, not a value, so the num is changed later. The num here also takes effect.Num++; ReturnPrintNum;}VarMyfunc=OuterFun (); myfunc ();// The output value is 101 instead of 100. // Another example. In the following example, we can see that anonymous functions (internal functions) are declared prior to external function variables, but still can access external function variables. // That is to say, the internal function and the external function variable are in the same closure, so you can access FunctionSameClosure (){VarICanAccess= Function() {Alert (name );};VarName= "Zhutao"; ReturnICanAccess;}VarTestSameClosure=SameClosure (); testSameClosure ();// Zhutao // Another application, concerning module pattern, can be called private, public, and other methods and variables. VarModule=(FunctionModule (){VarPrivateVar= "Zhutao is private"; // Private Return{PublicGetPrivateVar: Function(){ReturnPrivateVar;}, // Public method, which can be a so-called private variablePublicVar: "I'm a public variable" // Public variable};})();If(Flag) {alert (module. publicGetPrivateVar ());// Zhutao is privateAlert (module. publicVar );// I'm a public variableAlert (module. privateVar );// Undefined}
Closure Efficiency
Because the actual application of closure may generate an internal function multiple times (anonymous), there may be efficiency problems (Object creation, memory management and release ).
Therefore, we should try to reduce the generation of internal functions and use function references.
For example:
// Example of efficiencyFlag= False; // In this way, the overhead of the anonymous function is generated every time you call Outer. FunctionOuter (obj) {obj. fun= Function() {Alert ("I am" + This. Name );};}If(Flag ){VarObj={Name: "Zhutao"}; Outer (obj); obj. fun ();}// Better processing method FunctionOuter_better (obj) {obj. fun=Showme; // Only the reference of the function is called in this way.}FunctionShowme () {alert ("I am" + This. Name );}If(Flag ){VarObj2={Name: "Zhutao"}; Outer_better (obj2); obj2.fun ();}
Application suggestions
Don't use closures unless you really need closure semantics. In most cases, nonnested functions are the right way to go. Eric Lippert, Microsoft
The above discussion is based on efficiency, while IE 4-6 May have memory leakage when using closure. For details, refer to the related section in JavaScript Closures.
In some scenarios, you may have to use closure, suchLoop Problems.
Code:
Flag= True; // Generate links to the body and bind events FunctionAddLink (num ){For(VarI= 0;I<Num;I++){VarLink= Document. CreateElement ('A'); Link. innerHTML= "Link" +I;Link. onclick= Function() {Alert (I );};Document. Body. appendChild (link );}}// Unfortunately, when you click each Link, Link 4 is output. // Use closure to solve this problem FunctionAddLink2 (num ){For(VarI= 0;I<Num;I++){VarLink= Document. CreateElement ('A'); Link. innerHTML= "Link" +I;Link. onclick= Function(J ){// Use closure Return Function() {Alert (j );};// Returns a function.} (I );// Call this function Document. Body. appendChild (link );}}Window. Onload=AddLink (4);Window. Onload=AddLink2 (4);
Why is the above problem? (In fact, the same problem was encountered in the previous project, but closure was not understood at the time, and it was also difficult to understand)
This is because, for addLink, I has changed to 4 before exiting the addLink function. Therefore, no matter the subsequent event is triggered, all output is 4.
However, the latter uses closure. So that j references the I in the current loop, so the corresponding results will be obtained for each subsequent trigger event as expected.
The specific discussion is as follows: SO
This is a typical closure Application Scenario. If it is not used, it cannot be solved.
Conclusion
The following section is excerpted from Summary of JavaScript closures:
- When you use another function in a function, a closure is generated.
- When you use eval (), a closure is generated.
- It is best to think that closure is always generated at the function entrance, and the local variable is automatically added to closure.
For other details, refer to the above link.
In short, you must remember the following points about closure:
- Closure provides a mechanism for variable sharing (internal functions can access external function variables)
- Pay attention to the efficiency issues that closure may reference (for how to avoid them, refer to the details in this article)
- Be familiar with specific application scenarios
The previous blog post is about prototype, which is expected to be discussed in the next blog.This keyword. You are welcome to discuss and leave a message.
References
- JavaScript Closures
- Explaining JavaScript Scope And Closures
- JavaScript Closures 101
- JavaScript and memory leaks
- Closures in JavaScript
Rst source code in this article
The source code of this article is here.
The javascript code involved in this article can be downloaded here.
You can also choose to download pdf to read.