Javascript nested functions and closures

Source: Internet
Author: User

Nested Functions]
JavaScript allows embedded functions that can be used as data. Under the function lexical scope, it can generate an astonishing difference from the traditional object-oriented language.
First, JavaScript Functions use lexical division of scopes, rather than dynamic division of scopes. Therefore, functions are run in the scope that defines them, instead of running them in the execution scope, it is easy to understand when nested functions and their peripheral functions are defined in the same lexical scope. For example, the following simple code:
Copy codeThe Code is as follows:
Var x = 'global ';
Function f (){
Var x = 'local ';
Function g (){
Alert (x );
}
G ();
}
F (); // 'local'

When f () is called, The scope chain can be understood as composed of two parts, including the call object of f, followed by a global object. In this case, the value of x is first searched from the calling object of f. If not, x is located in the global object. Similarly, because g is a nested function of f, the scope chain should be composed of three parts: the call object of g and the call object of f, and global objects. The function g is to output the value of x, so it first searches for the value of x in the calling object of g, but does not define it in g. Then it looks for the definition of x in the object of the peripheral F call, then, if x = 'local' is found, x is output, rather than searching for global objects. If the value of x is not defined in f, the global object after the scope chain will be searched. The result is global. If the global object is not defined, it is undefined.
Well, we have a preliminary understanding of the scope chain. At the same time, we know that the closure has two common uses. One is that it can be used to access local variables, the other is to store the variable values in its peripheral scope in the memory instead of destroying them after the function is called.
Next, let's take a look at an unremarkable example, which may help you understand why closures can store external variable values in the memory.
Copy codeThe Code is as follows:
Function makeFunc (x ){
Return function () {return x ++}
}
Var a = [makeFunc (0), makeFunc (1), makeFunc (2)];
Alert (a [0] ();
Alert (a [1] ();
Alert (a [2] ();

The execution result is 0, 1, 2, and there is nothing special, which is also the normal performance of strict lexical scopes. After each makeFunc call is completed, its call object will be removed from the scope chain without any reference to it and will end with garbage collection. We can understand it in this way.
Each time makeFunc calls, it creates a call object for it and places it in the scope chain. For the makeFunc function, the called object contains an attribute x (that is, the function parameter, because the function parameter can be seen as an attribute of the called object ), makeFunc returns a reference to an anonymous nested function. Then, this anonymous nested function is executed and a call object is created and placed in the scope chain. The anonymous function returns the value of x. (Note: the call object of an anonymous function does not have the definition of x, so it will reference the call object of makeFunc of its peripheral function and access x) and then add 1 to x. So far, after an anonymous function is executed, the called object is removed from the scope chain, makeFunc is executed, and makeFunc is also removed. Since its call object contains x, x is destroyed as it is destroyed. Not saved.
The above is the detailed execution process of the function. Please take a closer look at the code changed below:
Copy codeThe Code is as follows:
Var x = 0;
Function makeFunc (){
Return function () {return x ++}
}
Var a = [makeFunc (), makeFunc (), makeFunc ()];
Alert (a [0] ();
Alert (a [1] ();
Alert (a [2] ();

Now x is a global variable and the execution result is 0, 1, 2. But this result is different from the above one. Next we will understand the cause of this result from the direction of the scope chain.
Similarly, each time makeFunc calls a call object, it creates a call object to the scope chain. Because it returns reference to internal nested functions, internal nested functions are executed, create a nested function call object to the scope chain. Then return the value of x. Note that this is different. The Calling object of the nested function does not contain x, and the calling object of makeFunc outside it does not contain x, you can only find the Global Object and find the definition of x in the global object. Therefore, the system runs normally and returns the value of x, which is added to 1. Then, the nested function is complete, after the call object is removed, makeFunc is complete and the call object is also removed. However, because no x exists in their call objects, the destruction of their call objects will not affect x. Therefore, the change of the global variable x value is saved.
Note: The above-mentioned access to the peripheral call object is only for the purpose of understanding but not strict, JavaScript will not directly access the call object in any way, however, it defines attributes as part of the scope chain in the calling object and is still "active ". In addition, if a peripheral function contains two or more nested functions that reference global objects, these nested functions share the same global call object, and one of the changes to the global object is visible to others.
Well, in JavaScript, a function is a combination of the code to be executed and the scope of the code to be executed. In a broad sense, we can call this combination of code and scope a closure.
Closure]
We occasionally need to write a function that needs to be called to remember a variable value. Therefore, if we understand the scope, we will know that local variables are difficult to achieve, because the function call object cannot be maintained after the call. Global variables can be achieved, just like the above example, but this can easily cause global variable pollution. Since the call object cannot be maintained, we will not save the value in the call object ?! Therefore, the following is a method of implementation: save with the attributes of the function object.
Copy codeThe Code is as follows:
UniqueID = function (){
If (! Arguments. callee. id) arguments. callee. id = 0;
Return arguments. callee. id ++;
}
Alert (uniqueID (); // 0
Alert (uniqueID (); // 1

As shown above, because a function itself is an object, it is feasible to store it with its own attribute, but there is a problem in doing so, that is, anyone can use the unqueID at any time. id to force access to the value we originally saved and make changes. This is what we don't want to see.
Therefore, we usually use closures to implement this. As follows:
Copy codeThe Code is as follows:
_ UniqueID = (function (){
Var id = 0;
Return function () {return id ++}
})();
Alert (_ uniqueID (); // 0
Alert (_ uniqueID (); // 1

Similarly, we also use the chain domain to explain the results. Note that _ uniqueID is an anonymous function, and there is an anonymous nested function inside it. We directly call _ uniqueID (), that is, we directly call the nested function inside _ uniqueID, but its own call object does not have a defined id, so we reference the id in the peripheral call object and return, id plus 1, after the execution is completed, the inner nested function calls the object out of the scope chain. The peripheral id is not destroyed, so it is saved.
Some people may wonder, isn't it because the called object removes the scope chain after the function execution is complete? The external anonymous function () {}) (); is also called complete, the call object should be no longer available.
Yes, the call object ends the reference after the current function is executed. But here, do not misunderstand the call of the above _ uniqueID (). It is not a peripheral function called directly, instead, it calls nested functions. The scope chain of nested functions contains the scope chain of peripheral functions. Therefore, when its calling object removes the scope chain, it can access and change the attributes of other objects on the scope chain.
The closure itself is hard to understand but very useful. I hope it can help people who need it. In addition, the qualifications are limited and I may understand them incorrectly. If you find them, please correct them.

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.