Javascript: Closure

Source: Internet
Author: User
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.

 VaR Flag =   False  ;    // Debug Switch  // Env is the so-called Environment  // Inner is the so-called expression, and name is the so-called free variable  Function ENV () // The entire env can be regarded as a closure { VaR Name =   "Zhutao"  ;  Function Inner (){ Return Name +  "Is a student ."  ; } Return Inner ;     // An internal function is returned. } // Closure ends Flag =   True  ;  If (FLAG ){ // This is the most amazing place,CodeThe inner function has actually output the Env body,  // But it can still be referenced. This is called closure. VaR Inner_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.Article 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 example Flag =  True  ;  VaR Tmpobj = {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 applications Flag =   True  ;  Function Outerfun (){VaR Num =   100;  VaR Printnum =   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 ++;  Return Printnum ; } VaR Myfunc = 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  Function Sameclosure (){ VaR Icanaccess =   Function () {Alert (name );}; VaR Name =   "Zhutao"  ; Return Icanaccess ; } VaR Testsameclosure = Sameclosure (); testsameclosure (); // Zhutao  // Another application, concerning module pattern, can be called private, public, and other methods and variables.  VaR Module = ( Function Module (){ VaR Privatevar =  "Zhutao is private"  ;     // Private  Return {Publicgetprivatevar :   Function (){ Return Privatevar ; } ,    // Public method, which can be a so-called private variable Publicvar :   "I'm a public variable"  // Public variable };})(); If (FLAG) {alert (module. publicgetprivatevar ()); // Zhutao is private Alert (module. publicvar ); // I'm a public variable Alert (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 efficiency Flag =  False  ;  // In this way, the overhead of the anonymous function is generated every time you call outer.  Function Outer (OBJ) {obj. Fun =   Function () {Alert ( "I am"   +   This . Name );};} If (FLAG ){ VaR OBJ = {Name :  "Zhutao" }; Outer (OBJ); obj. Fun ();} // Better processing method  Function Outer_better (OBJ) {obj. Fun = Showme ;     // Only the reference of the function is called in this way. } Function Showme () {alert ( "I am"   +   This . Name );} If (FLAG ){ VaR Obj2 = {Name :   "Zhutao" }; Outer_better (obj2); obj2.fun ();}
Application suggestions
 
Don't use closures unless youreally need closure semantics. In most cases, nonnestedfunctions 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 Function Addlink (Num ){ For ( VaR I = 0; I < Num ; I ++ ){ VaR Link =   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  Function Addlink2 (Num ){ For ( VaR I = 0; I< Num ; I ++ ){ VaR Link =   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:

    1. When you use another function in a function, a closure is generated.
    2. When you use eval (), a closure is generated.
    3. 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:

    1. Closure provides a mechanism for variable sharing (internal functions can access external function variables)
    2. Pay attention to the efficiency issues that closure may reference (for how to avoid them, refer to the details in this article)
    3. 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
    1. Javascript closures
    2. Explaining JavaScript scope and closures
    3. Javascript closures 101
    4. JavaScript and memory leaks
    5. 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.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.