Original article: Understanding JavaScript closures
To become advanced JavascriptProgramYou must understand the closure.
This document describes the internal working mechanism of closures in conjunction with The ECMA 262 specification, it allows JavaScript programmers to understand closures from "nested functions" to the running mechanism behind JavaScript objects such as "identifier parsing, execution environment and scope chain, truly understand the essence of closure.
Original article: javascript closures
Printable version: javascript Closure
Directory
- Introduction
- Object Property name resolution
- Value assignment
- Read Value
- Identifier parsing, execution environment, and scope chain
- Execution Environment
- Scope chain and [[Scope]
- Identifier resolution
- Closure
- Automatic garbage collection
- Closure
- What can be done through closures?
- Example 1: Set latency for function reference
- Example 2: Associate functions using object instance methods
- Example 3: Packaging-related functions
- Other examples
- Unexpected Closure
- Internet Explorer Memory leakage
Introduction
Returned directory
-
Closure
-
A closure refers to an expression (usually a function) with many variables and an environment bound to these variables. Therefore, these variables are part of the expression.
Closure is one of the most powerful features of ecmascript (JavaScript), but the premise of using closure well is that you must understand the closure. The creation of closures is relatively easy. People may even inadvertently create closures, but these unintentional closures have potential dangers, especially in Common Browser environments. If you want to use closures, you must understand their working mechanism. The implementation of the closure mechanism depends largely on the role in the scope of the identifier (or object attribute) parsing process.
The simplest description of closures is that ecmascript allows internal functions-that is, function definitions and function expressions are located in the body of another function. In addition, these internal functions can access all the local variables, parameters, and other declared internal functions declared in their external functions. When one of these internal functions is called outside the external functions that contain them, a closure is formed. That is to say, the internal function will be executed after the external function returns. When this internal function is executed, it must still access the local variables, parameters, and other internal functions of its external function. The values of these local variables, parameters, and function declarations (initially) are the values returned by external functions, but they are also affected by internal functions.
Unfortunately, to properly understand a closure, you must understand the mechanism behind the closure and many related technical details. Although the first half of this article does not involve some ofAlgorithmBut there is still a lot of content that cannot be avoided or simplified. For some people who are familiar with object property name resolution, you can skip the relevant content, but unless you are familiar with closures, it is best not to skip the following sections.
Object Property name resolution
Returned directory
Ecmascript recognizes two types of objects: Native objects and host objects, the Host object contains a subclass of the native object called the built-in object (ECMA 262 3rd ed section 4.3 ). The native object is a language, and the host object is provided by the environment. For example, it may be a document object, Dom, and other similar objects.
Native objects have loose and dynamic naming attributes (for some implemented built-in object subcategories, the dynamic nature is limited-but this is not a big problem ). The object naming attribute is used to save a value. This value can be a reference to another object (in this sense, a function is also an object ), it can also be some basic data types, such as string, number, Boolean, null, or undefined. Specifically, the undefined type is used, because you can specify a value of the undefined type for the object attribute without deleting the corresponding attributes of the object. In addition, this property only saves the undefined value.
Next, we will briefly introduce how to set and read the attribute values of an object and reflect the internal details to the maximum extent.
Value assignment
Returned directory
You can assign a value to an object or assign a value to it. That is,:
VaR objectref = new object (); // create a common JavaScript Object.
You can use the following statement to create an attribute named "testnumber:
Objectref. testnumber = 5;
/*-Or -*/
Objectref ["testnumber"] = 5;
Before the value assignment, the object does not have the "testnumber" attribute, but after the value assignment, an attribute is created. You do not need to create this attribute for any subsequent value assignment statement, but will only reset its value:
Objectref. testnumber = 8;
/*-Or :-*/
Objectref ["testnumber"] = 8;
We will introduce later that JavaScript objects all have prototypes attributes, and these prototypes are also objects, so they can also have named attributes. However, the role of the naming attribute of the prototype object is not reflected in the value assignment stage. Similarly, when a value is assigned to its name attribute, if the object does not have this attribute, the name attribute will be created; otherwise, the value of this attribute will be reset.
Read Value
Returned directory
When reading the attribute values of an object, the role of the prototype object is displayed. If the object's prototype contains the property name used by the property accessor, the value of this property will return:
/* Assign a value to the name attribute. If the object does not have an Attribute before the value is assigned, the following result is displayed after the value is assigned :*/
Objectref. testnumber = 8;
/* Read value from attribute */
Var val = objectref. testnumber;
/* Now,-Val-Saves the 8 */
In addition, because all objects have the original type, and the prototype itself is also the object, the prototype may also have the original type, thus forming the so-called prototype chain. The prototype chain ends with an object whose original type is null.Object
The default prototype of the constructor has a null prototype. Therefore:
VaR objectref = new object (); // create a common JavaScript Object.
Create a prototypeObject. Prototype
And the prototype itself has a prototype with a null value. That is to say,Objectref
The prototype chain contains only one object --Object. Prototype
. But for the followingCodeNote:
/* Create-myobject1-type object function */
Function myobject1 (formalparameter ){
/* Add an attribute named-testnumber-to the created object
Specify the first parameter passed to the constructor as the attribute value :*/
This. testnumber = formalparameter;
}
/* Create-myobject2-type object function */
Function myobject2 (formalparameter ){
/* Add an attribute named-teststring-to the created object.
Specify the first parameter passed to the constructor as the attribute value :*/
This. teststring = formalparameter;
}
/* In the next operation, replace all the prototypes associated with the myobject2 instance with the myobject1 class instance. Besides, the-8-parameter is passed for the myobject1 constructor. Therefore, the-testnumber-attribute is assigned this value :*/
Myobject2.prototype = new myobject1 (8 );
/* Finally, use a string as the first parameter of the constructor, create an instance of-myobject2-, and assign the reference pointing to this object to the variable-objectref -:*/
VaR objectref = new myobject2 ("string_value ");
VariableObjectref
ReferencedMyobject2
The instance has a prototype chain. The first object in the chain is specifiedMyobject2
ConstructorPrototype
AttributeMyobject1
.Myobject1
The instance also has a prototype, that isObject. Prototype
The prototype of the default object corresponding to the referenced object. Finally,Object. Prototype
There is a prototype with a value of null, so this prototype chain ends here.
When an attribute accessor attempts to readObjectref
When the attribute value of the referenced object is used, the entire prototype chain is searched. In the following simple case:
Var val = objectref. teststring;
BecauseObjectref
ReferencedMyobject2
The instance has an attribute named "teststring", so the value of this attribute set to "string_value" is assigned to the variableVal
. However:
Var val = objectref. testnumber;
You cannotMyobject2
The instance itself reads the corresponding named property value because the instance does not have this property. However, variablesVal
Is still set8
Instead of being undefined -- this is because the interpreter will continue to check its prototype object after the corresponding name attribute fails to be searched in the instance. The prototype object of this instance isMyobject1
The instance has an attribute named "testnumber" and its value is8
, So this attribute accessors will get the final value8
. Besides, althoughMyobject1
AndMyobject2
Are Not DefinedTostring
Method, but when the property accessors passObjectref
ReadTostring
When the attribute value is:
Var val = objectref. tostring;
VariableVal
It is also assigned a function reference. This function isObject. Prototype
OfTostring
The function saved in the property. This function is returned because a search is performed.Objectref
The process of prototype chain. WhenObjectref
If no "tostring" attribute exists, the system searches for its prototype object. If this attribute does not exist in the prototype object, the system searches for the prototype. The final prototype in the prototype chain isObject. Prototype
This object does haveTostring
Method, so the reference of this method is returned.
Finally:
Var val = objectref. madeupproperty;
ReturnUndefined
Because in the process of searching the prototype chainObject. Prototype
The prototype -- null, does not find any attribute of the object named "madeuppeoperty", so the final returnUndefined
.
Whether in an object or an object's prototype, when reading a named property value, only the attribute value first found is returned. When assigning values to the object's naming attribute, if the object does not own this attribute, the corresponding attribute is created.
This means that ifObjectref. testnumber = 3
This is a value assignment statement.Myobject2
The instance itself will also create an attribute named "testnumber", and any attempt to read this name attribute will get the same new value. At this time, the property accessors will not further search for the prototype chain,Myobject1
The instance value is8
The "testnumber" attribute of is not modified. ToObjectref
The assignment of objects only blocks the corresponding attributes in the prototype chain.
Note: ecmascript defines an internal[[Prototype]
Attribute. This attribute cannot be directly accessed through a script. However, this internal attribute must be used during the parsing process of the property accessor.[[Prototype]
The object chain referenced by the property, that is, the prototype chain. You can use a publicPrototype
Attribute[[Prototype]
Assign values or define the prototype object corresponding to the property. The relationship between the two is described in detail in ECMA 262 (3rd edition), but beyond the scope of this article.
Identifier parsing, execution environment, and scope chain execution environment
Returned directory
The execution environment is an abstract concept used by ecmascript specifications (ECMA 262 3rd) to define ecmascript to implement necessary behaviors. There are no provisions on how to implement the execution environment. However, because the execution environment contains the relevant attributes of the structure defined by the reference specification, the execution environment should have (or even implement) objects with attributes, even if the attributes are not public attributes.
All JavaScript code is executed in an execution environment. Global Code (Code executed as a built-in JS file, orHtml
Page Load Code) is executed in the execution environment I call the "Global execution environment", and each call to the function (
It may be a constructor). It also has an associated execution environment. PassEval
Function Execution Code has a completely different execution environment, but JavaScript programmers generally do not useEval
So we will not discuss it here. For more information about the execution environment, see Section 262 of ECMA 10.2 (3rd edition.
When a JavaScript function is called, the function enters the corresponding execution environment. If another function is called (or the same function is called recursively), a new execution environment is created and the execution process is in this environment during the function call. When the called function returns, the execution process returns the original execution environment. Therefore, the running JavaScript code constitutes an execution environment stack.
During the creation of the execution environment, a series of operations are completed in the defined sequence. First, an "activity" object is created in the execution environment of a function. The activity object is another mechanism specified in the specification. An object is called an object because it has an accessible naming attribute, but it does not have a prototype (at least no predefined prototype) as a normal object ), in addition, the active object cannot be directly referenced through JavaScript code.
The next step for creating an execution environment for function calls is to createArguments
Object, which is an array-like object. It stores the parameters passed when calling a function one by one based on the array members of the integer index. This object also hasLength
AndCallee
Attributes (these two attributes have nothing to do with the content we discuss. For details, see the specifications ). Then, an attribute named "arguments" will be created for the activity object, which references the previously createdArguments
Object.
Then, assign a scope for the execution environment. The scope is composed of object lists (chains. Each function object has an internal[[Scope]
Attribute (this attribute will be described in detail later), which is also composed of the Object List (chain. Specifies the scope of the execution environment for a function call.[[Scope]
The list of objects referenced by the property. At the same time, the activity object is added to the top of the Object List (the front-end of the chain ).
Then the process of "variable instantiation" is completed by the so-called "variable" Object in ECMA 262. In this case, the activity object is used as a variable object (it is important to note that they are the same object ). In this case, the form parameters of the function are created as variable object naming attributes. If the parameters passed during function calling are the same as those of the form parameters, the value of the corresponding parameter is assigned to these naming attributes (otherwise, the name attribute is assignedUndefined
Value ). For a defined internal function, an attribute with the same name is created for the variable object when it is declared, and the corresponding internal function is created as a function object and specified to this attribute. The last step of variable instantiation is to create all the local variables declared in the function as variable object naming attributes.
Attributes of a variable object created based on declared local variables are assigned During Variable instantiation.Undefined
Value. No real instantiation of local variables is performed before the code in the function body is executed and the corresponding value assignment expression is calculated.
In factArguments
The activity object of the property and the variable object with the name attribute corresponding to the local variable of the function are the same object. Therefore, the identifierArguments
As a local variable of the function.
Finally, to useThis
Keyword. If the assigned value references an object, the prefix isThis
The attribute accessors of the keyword refer to the attributes of the object. If the assigned (internal) value is nullThis
The global object is referenced by the keyword.
The process of creating a global execution environment is slightly different because it does not have parameters, so you do not need to reference these parameters by defining activity objects. However, the global execution environment also requires a scope, and its scope chain is actually composed of only one object-Global Object. The global execution environment also involves variable instantiation. Its internal functions are standard top-level function declarations involving most JavaScript code. In addition, global objects are variable objects during variable instantiation, Which is why global declared functions are attributes of global objects. The same applies to variables declared globally.
The global execution environment will also useThis
To reference global objects.
Scope chain and [[Scope]
Returned directory
The execution environment created when a function is called contains a scope chain. This scope chain adds the activity (variable) Objects of the execution environment to the ones saved to the called function objects.[[Scope]
The frontend of the scope chain in the attribute. Therefore, understand[[Scope]
The attribute definition process is crucial.
In ecmascript, functions are also objects. Function objects are created based on function declarations during variable instantiation, or when function expressions or calls are calculated.Function
Create a constructor.
By callingFunction
The function object created by the constructor.[[Scope]
The scope chain referenced by the property always contains only global objects.
Function objects created through function declaration or function expressions[[Scope]
The attribute references the scope chain that creates their execution environment.
In the simplest case, for example, declare the following global functions :-
Function examplefunction (formalparameter ){
... // Code in the function body
}
-When variables are instantiated to create a global execution environment, corresponding function objects are created according to the above function declaration. Because the scope chain of the global execution environment only contains global objects, it gives internal function objects created by itself and referenced by Attributes named "examplefunction ".[[Scope]
Attribute, giving the scope chain that contains only global objects.
When a function expression is calculated in a global environment, a similar process of specifying a scope chain occurs :-
VaR examplefuncref = function (){
... // Function body code
}
In this case, the difference is that during the Global execution environment variable instantiation process, a naming attribute is created for the Global Object first. Before the value assignment statement is calculated, the function object is not created or referenced to the global object. However, this function object will still be created in the global execution environment (when the function expression is calculated. For this function object[[Scope]
The scope chain specified by the attribute still contains only global objects. Internal function declarations or expressions can create corresponding function objects in the execution environment of the external functions that contain them. Therefore, the scope chains of these function objects are slightly more complex. In the following code, an external function with internal function declaration is defined and then an external function is called:
/* Create a global variable-y-which references an object:-*/var y = {X: 5 }; // function examplefuncwith () {var Z;/* adds the Global Object-y-referenced object to the front end of the scope chain: -*/with (y) {/* evaluate the function expression to create a function object and assign the reference of this function object to the local variable-z -: -*/z = function (){... // Code in the internal function expression ;}}...} /* Execute-examplefuncwith-function :-*/
Examplefuncwith ();Examplefuncwith
The execution environment created by the function contains a scope chain composed of its active objects and global objects. While executingWith
The global variableY
The referenced object is added to the frontend of the scope chain. In the process of evaluating the function expression[[Scope]
The attribute is consistent with the scope of the execution environment where it is created -- that is, this attribute references an objectY
The activity object of the execution environment created when an external function is called, And the scope chain of the global object.
WhenWith
When statement blocks are executed, the scope of the execution environment is restored (Y
Will be removed), but the created function object (Z
. Note by the translator)[[Scope]
Objects at the beginning of the scope chain referenced by the attribute are still objects.Y
.
Example 3: Packaging-related functions
Returned directory
Closures can be used to create additional scopes that organize relevant and dependent code to minimize the risk of unexpected interactions. Suppose there is a function used to build a string. To avoid repetitive join operations (and to create many intermediate strings), we wish to use an array to store all parts of the string in order, and then useArray. Prototype. Join
Method (using an empty string as its parameter) to output the result. This array will be used as the buffer for output, but using the array as the local variable of the function will lead to the re-creation of a new array every time the function is called, this is not necessary when only variable content in the array is re-specified during each function call.
One solution is to declare this array as a global variable, so that you can reuse this array without having to create a new array every time. However, the result of this solution is that in addition to the global variables that reference the function, this buffer array will be used, and an additional global attribute will reference the array itself. This not only makes the code difficult to manage, but also requires developers to define functions and arrays again to use this array elsewhere. In this way, the Code cannot be easily integrated with other codes, because it is not only necessary to ensure that the name of the function used is unique in the global namespace, make sure that the array on which the function depends must also be unique in the global namespace.
Through the closure, the array used as the buffer can be associated with the function dependent on it (elegantly packaged), and the attribute name of the buffer array specified outside the global namespace can be maintained, removes the risk of name conflicts and unexpected interactions.
The key technique is to create an additional execution environment by executing an in-line function expression, and use the internal function returned by the function expression as the function used in external code. In this case, the buffer array is defined as a local variable of the function expression. This function expression only needs to be executed once, And the array only needs to be created once, which can be reused by functions dependent on it.
The following code defines a function, which is used to return an HTML string. Most of the content is constants, but variable information needs to be interspersed in these constant character sequences, variable information is provided by parameters passed when a function is called.
Returns an internal function by executing a single row function expression and assigns the returned function to a global variable. Therefore, this function can also be called a global function. The buffer array is defined as a local variable of the external function expression. It is not exposed to the global namespace, and no matter when the function dependent on it is called, the array does not need to be re-created.
/* Declare a global variable-getimginpositioneddivhtml-and assign the internal function returned by calling an external function expression at a time. This internal function will return a div element used to indicate absolute positioning and enclose the HTML of an IMG element.In this way, all variable attribute values are provided by the parameter when the function is called: */var getimginpositioneddivhtml = (function () {/* The local variable of the external function expression-buffar-stores the buffer array. This array is created only once, and the generated array instance is always available for internal functions, so it can be used every time this internal function is called. The Null String is used as a data placeholder. The corresponding data is inserted into the array by the internal function: */var buffar = ['<Div id = "',", // Index 1, div ID attribute '"style =" position: absolute; top:', ", // index 3, div top position 'px; left :',", // index 5, left side of the DIV 'px; width: ', ", // index 7, div width 'px; Height:',", // index 9, div height 'px; overflow: hidden; "> </div>'];/* returns the internal function object that is used as the result after the function expression is evaluated. This internal function is the function called and executed every time-getimginpositioneddivhtml (... )-*/Return (function (URL, ID, width, height, top, left, alttext) {/* insert different parameters to the corresponding position of the buffer array: */buffar [1] = ID; buffar [3] = top; buffar [5] = left; buffar [13] = (buffar [7] = width ); buffar [15] = (buffar [9] = height); buffar [11] = URL; buffar [17] = alttext; /* returns the string formed by concatenating each element of the array using an empty string (equivalent to concatenating array elements): */return buffar. join (") ;}); //: the internal function expression ends .}) ();/* ^-: Single-row external function expression. */
If a function depends on one or more other functions, and other functions are not directly called by other code, you can use the same technology to wrap these functions, they are called through a publicly exposed function. In this way, a complex multi-function processing process is encapsulated into a portable code unit.
Other examples
One of the most widely known applications about closures is Douglas crockford's technique for the emulation of private instance variables in ecmascript objects. This application method can be extended to the scope structure of various nested accessible (or visibility), including the emulation of Private Static members for ecmascript objects.
The possible use of a closure is unlimited. Understanding how it works is the best guide to how to use it.
Unexpected Closure
Returned directory
Parsing the internal function outside the function body that creates an accessible internal function constitutes a closure. This indicates that the closure is easy to create, but this may lead to a result that the closure is not recognized as a javascript author of a language feature, internal functions are used based on the idea that internal functions can complete multiple tasks. However, they are not clear about the results of using internal functions, and do not even realize what they mean by creating closures or doing so.
As mentioned in the next section about memory leakage in IE, accidental closures may cause serious negative effects and affect the code performance. The problem is not the closure itself. If you can use them with caution, it will help you create efficient code. In other words, using internal functions affects efficiency.
One of the most common cases of using internal functions is to use them as the event processor of DOM elements. For example, the following code adds an onclick event processor to a link element:
/* Define a global variable. Use the following function to add its value as part of the query string to the-href-link: */var quantaty = 5; /* When a link (as the function parameter-linkref-) is passed to this function, an onclick event processor is assigned to this link, the event processor adds the value of the global variable-quantaty-to the-href-attribute of the link as a string, then return true to locate the resource specified by the query string contained in the-href-attribute after the link is clicked: */function addglobalqueryonclick (linkref) {/* If the parameter-linkref-can be converted to ture by type (meaning it references an object): */If (linkref) {/* evaluate a function expression, and assign the reference to this function object to the onclick event processor of this link element :*/ Linkref. onclick = function () {/* this internal function expression adds the query string to the-href-attribute of the element appended with the event processor: */This. href + = ('? Quantaty = '+ escape (quantaty); Return true ;};}}
WheneverAddglobalqueryonclick
A new internal function is created (the closure is formed by assigning values ). From the perspective of efficiency, if you only callAddglobalqueryonclick
There is no major obstacle to the function, but frequent use of this function will lead to the creation of many completely different function objects (each evaluate the value of the internal function expression, will generate a new function object ).
The code in the above example does not focus on the fact that internal functions can be accessed (or make up closures) outside the function that is created. In fact, the same effect can be achieved in another way. Define a function for the event processor separately, and then assign the reference of the function to the event processing attribute of the element. In this way, you only need to create a function object, and all elements using the same event processor can share the reference to this function:
/* Define a global variable. Use the following function to add its value as part of the query string to the-href-link: */var quantaty = 5; /* When a link (as the function parameter-linkref-) is passed to this function, an onclick event processor will be added to this link, the event processor adds the global variable-quantaty-to the link-href-as part of the query string, and returns true, to locate the resource specified by the query string as the-href-attribute value when you click the link: */function addglobalqueryonclick (linkref) {/* If the-linkref-parameter can be converted to true by type (meaning it references an object): */If (linkref) {/* specify a reference to the global function to the event processing attribute of the link to make the function the event processor of the link element: */Linkref. onclick = foraddqueryonclick;}/* declares a global function as the event processor of the link element, this function uses the value of a global variable as part of the-href-value of the link element of the event processor to be added: */function foraddqueryonclick () {This. href + = ('? Quantaty = '+ escape (quantaty); Return true ;}
In the first version of the preceding example, internal functions do not function as closures. In that case, instead of using closures, it is more efficient, because you do not need to create multiple function objects that are essentially the same.
Similarly, it applies to object constructors. Code similar to the constructor framework in the following code is not uncommon:
Function exampleconst (PARAM) {/* evaluate the function expression to create an object, and assign the reference of the obtained function object to the property of the object to be created: */This. method1 = function (){... // Method body. }; This. method2 = function (){... // Method body. }; This. method3 = function (){... // Method body. };/* Assign the constructor parameter to an attribute of the object: */This. publicprop = Param ;}
Each timeNew exampleconst (N)
When you use this constructor to create an object, a group of new function objects are created as object methods. Therefore, the more object instances you create, the more function objects you need.
Douglas crockford's technique of imitating Private Members of JavaScript objects uses the closure formed by specifying references to internal functions to construct public attributes of objects in constructors. If the object method does not use the closure formed in the constructor, multiple function objects created when each object is instantiated will slow the instantiation process, in addition, more resources will be occupied to meet the needs of creating more function objects.
In this case, only the callback function objects are created, and they are specified to the constructor.Prototype
Is obviously more efficient. In this way, they can be shared by all objects created by the constructor:
Function exampleconst (PARAM) {/* assign the constructor parameter to an attribute of the object: */This. publicprop = Param;}/* method for creating an object by evaluating the function expression and specifying the reference of the result function object to the corresponding attribute of the constructor prototype: */exampleconst. prototype. method1 = function (){... // Method body .}; Exampleconst. Prototype. method2 = function (){... // Method body .}; Exampleconst. Prototype. method3 = function (){... // Method body .};
Internet Explorer Memory leakage
Returned directory
There is a problem in the garbage collection system of Internet Explorer Web browser (verified in IE 4 to IE 6), that is, if ecmascript and some host objects constitute a "circular reference ", these objects will not be collected as garbage. In this case, the so-called host object refers to any dom node (including the document object and its descendant elements) and ActiveX object. If one or more such objects are contained in a circular reference, these objects will not be released until the browser is closed, the memory they occupy will not be handed back to the system for reuse before the browser is closed.
When two or more objects are referenced by each other in the form of first-and-end links, a circular reference is formed. For example, an attribute of object 1 References object 2, an attribute of object 2 references object 3, and an attribute of object 3 references object 1. For pure ecmascript objects, as long as no other objects reference objects 1, 2, and 3, that is, they are only referenced between each other, they will still be identified and processed by the garbage collection system. However, in Internet Explorer, if any object in the circular reference is a DOM node or ActiveX object, the garbage collection system will not find that the circular relationships between them are isolated from other objects in the system and release them. Eventually they will be stored in the memory until the browser is closed.
Closure is very easy to construct circular references. If a function object that constitutes a closure is assigned, for example, an event processor of a DOM node, and a reference to this node is assigned to an activity (or variable) in the scope of the function object) object. Dom_node.onevent-> function_object. [[Scope]-> scope_chain-> activation_object.noderef-> dom_node. It is easy to form such a circular reference, and browsing a website containing similar circular reference code (usually in every page of the website) will consume a lot (or even all) system memory.
Pay more attention to avoid the formation of circular references. When it cannot be avoided, you can also use the compensation method. For example, you can use the onUnload Event of IE to clear (null) the reference of the event processing function. Always aware of this problem and understanding the working mechanism of closures is the key to avoiding such problems in IE.
Comp. Lang. Javascript FAQ notes T. o.c.
- Written by Richard Cornford, November March 2004
- Suggestions for modification come from:
- Martin honnen.
- Yann-erwan perio (Yep ).
- Lasse reichstein Nielsen. (definition of closure)
- Mike Scirocco.
- Dr John Stockton.