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.
Var flag = false; // debug switch // env is both the so-called Environment // and inner is the so-called expression, and name is the so-called free variable function env () // The entire env can be viewed as a closure {var name = "zhutao"; function inner () {return name + "is a student. ";}return inner; // returns an internal function} // closure end flag = true; if (flag) {// This is the most amazing place, code execution here, the inner function actually has an env body, // and can still be referenced. This is the so-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.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 context of global}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, instead of the value. Therefore, num is changed later. 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, however, you can still access the variables of the external function. // That is to say, the variables of the internal function and the external function 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, for module pattern, we can use the so-called private and public methods and variable var module = (function Module () {var privateVar = "zhutao is private "; // private return {publicGetPrivateVar: function () {return privateVar;}, // public method, which can be called the 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; // this calls only the reference of the function} 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 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 the event 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. // closure can solve this problem by using 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) ;}; // return 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.