This may be a classic problem that every jser once had a headache. It is related to memory, closure, and JavaScript operating mechanism. It depends on functions and performance.
ArticleThe content is mainly referred to in "High Performance JavaScript". This book is indeed in-depth on the Javascript performance. You can try to read it whenever you have time ,:English and Chinese versions.
Reviews, notes, and more in-depth understanding.
You are welcome to make corrections.
Scope:
Next we will first understand the following concepts:
- [[Scope] attributes of function objects, scopechain (scope chain)
- Execution context (runtime context) and activation object (activation object)
[[Scope] attributes:
Every function in Javascript is a function object (function instance). Since it is an object, there are related attributes and methods. [[Scope] is an attribute that each function object has for internal use only within the JavaScript engine. This attribute is a set (similar to the linked list structure ), and saves all objects in the scope of the function when it is created.Linked List formed by a set of scopesIt is calledScopechain (scope chain ).
The scope object stored in the scope chain is all the data that can be accessed by the function. For example (the example is from high performance JavaScript High Performance JavaScript):
FunctionAdd (num1, num2 ){
VaRSum = num1 + num2;
ReturnSUM;
}
Figure 1
When the Add function is created, the global objects in the global scope of the function are placed in the scope chain ([Scope] attribute) of the add function. We can see from figure 1 that the first object in the scope chain stores the global object, and the global object stores the Add function such as this, window, document, and global object, that is, his own. This is why we can access window (this), global variables, and function itself in a global function. Of course, the function scope is not global. We will discuss it later.
Execution context (runtime context) and activation object (activation object ):
(I saw Lao Luo's speech the day before yesterday. Lao Luo said that during the Chinese New Year, each person in the company should be given a refrigerator, and a new lock should be placed on all the toilets in the school buildings, make sure that your shoes are truly private .)
VaR Total = add (5, 10 );
When you start executing this function, an internal object of execution context will be created, this object defines the scope environment of the function Runtime (note that it is distinguished from the scope chain object [[Scope] During function creation. This is two different scope chain objects, in this way, I guess one is to protect [[Scope], and the other is to control the scope chain according to different runtime environments. Each execution of a function creates a separate execution context, which is equivalent to copying the scope chain of the function to the current execution context before each execution ). The execution context object has its own scope chain, which is initialized when the execution context is created, all content of the scope chain object [[Scope] During function creation will be copied to the scope chain of execution context in the order of [[Scope] scope chain.
At this point, a new object, activation object, will be inserted at the top of the scope chain of execution context. What is this activation object? This activation object stores all the parameters, real parameters, local variables, this pointer, and other data in the function during function execution. This activation object is a variable object, the data changes as the data changes during function execution. After the function execution is completed, the execution context will be destroyed and the scope chain of the execution context will be destroyed, of course, the activation object will be destroyed (but if there is a closure, the activation object will exist in another way, which is also the real cause of the closure, which will be discussed later .). Details:
Figure 2
From left to right, the first part is the execution context created during function execution. It has its own scope chain, and the second part is the objects in the scope chain, objects with an index of 1 are copied from the [[Scope] scope chain. Objects with an index of 0 are created during function execution, the third part is the activation object and Global Object content of objects in the scope chain.
When a function is running and does not encounter a variable, it searches from top to bottom in the scope chain of execution context. If it is in the first scope chain (for example, activation object) if this variable is not found, continue searching until it is found. That is why the function can access global variables, when a local variable has the same name as a global variable, local variables are used instead of global variables, and the answers to various seemingly weird and interesting scope questions in JavaScript (You can use this method to explain all the scope problems you encountered before. Of course, if you still have questions, I hope you can post them.Code, We will discuss it together.)
In general, the scope chain of a function will not be changed during function running, but some operators will temporarily change the scope chain, catch clauses of with and try catch. See the following example:
FunctionInitui (){
With (document ){// Avoid!
VaRBD = body,
Links = getelementsbytagname (""),
I = 0,
Len = links. length;
While(I <Len ){
Update (Links [I ++]);
}
Getelementbyid ("Go-BTN"). Onclick =Function(){
Start ();
};
BD. classname ="Active";
}// EOF
}
In the above example, the event processor of The onclick event references the local variable ID of the external function assignevents to form a closure. Let's take a look at their scope illustration:
Figure 4
Let's take a look at the closure formation process from the scope perspective:
-
- The assignevents function is created. After lexical parsing, the [[Scope] attribute of the function object assignevents is initialized and the scope chain is formed. The scope chain contains all attributes and methods of the Global Object (note, at this time, because the assignevents function is not executed, the closure function is not parsed ).
-
- Execute the assignevents function. When execution starts, create the execution context (we divide figure 4 into six parts in the order from left to right, from top to bottom, and the first part is the runtime context ), create an activation object (Part 2 and Part 3) in the scope chain of the runtime context, and place the activation object with the vertices of the scope chain, all data in the function that can be accessed during function execution is saved.
- when the closure is executed, the JavaScript engine finds the existence of the closure function. According to the common method, it parses the closure function and creates the [[Scope] attribute for the closure function object, initialize the scope chain (in this case, there are two objects in the scope chain of the closure function object, one is the activation object when the assignevents function is executed, and the other is the global object, 4, 5, and 6 in Figure 4 .). In the figure, is the scope chain of the closure function object the same as the execution context chain of the assignevents function? Why are they the same? Let's analyze it. The closure function is found and parsed during the execution of the assignevents function, and the scope of the function execution is activation object, so the result is obvious, when a closure function is parsed, its scope is exactly the first scope object activation object in the assignevents scope chain. Of course, due to the relationship between the scope chain, the global object scope is also introduced into the scope chain of the closure function. So now we have another question: does the activation object in the closure scope chain reference the activation object of the assignevents function, or does it copy a copy to the closure scope chain? We can perform a small test. When multiple closures reference the outer function local variable (I) at the same time, if one of the closures changes the content of I, if the content of I in other closures is not changed, a copy is generated. Otherwise, the same activation object is referenced.
-
function FN () {
var I = 0; ( function () {++ I; console. log (I)}) ();
( function () {++ I; console. log (I )})();
}
FN ();
// 1 // 2
- We found that the variable I changed from 1 to 2, which means that the two closures reference the same variable I, that is, they reference the same FN activation object, in fact, it can be explained in a very simple way: the Global object must be the same, right?
- The following describes how to execute a closure function, because during lexical analysis, the closure function has saved a reference to the activation object of the assignevents function in the scope chain, so after the assignevents function is executed, although the closure function has not started execution, it can still access the local data of assignevents (not because the closure function needs to access the local variable ID of assignevents, therefore, after the assignevents function is executed, the local variable ID is still referenced. However, no matter whether a variable reference exists, the reference to the activation object scope object of assignevents will be saved. During lexical analysis, the closure function is not executed, and the function does not know whether to access and operate the local variables of assignevents, therefore, the activation object scope object of assignevents can only be saved first. When the closure function is executed, if you need to access the local variables of assignevents, then search in the scope chain ).
- When the closure function is executed, it creates its own execution context and activation object, saves its own activation object in the scope chain of the runtime context, and activation object of the execution context of the assignevents function, and global object,
Figure 5
This is why the closure can "remember" What happened around it and why it can access the local data of the outer function, the reason why the closure can keep the local data and not destroy it when the outer function is executed and destroyed.
A predecessor (Darrel Uncle Wen) told me a few days ago that there is no memory and no closure.
Performance problems:
The performance problems in the scope chain and closure are mainly manifested in the speed of data reading and writing.
Because of the scope chain, we access the global scope data (why not mention the variables here? Because it includes not only variables, but also functions, objects, and other content), the efficiency is the lowest, and the access to local data is the highest.
Therefore, a very classic solution to data access performance problems emerged: cache the data to be accessed as much as possible in the form of local data. In this way, when the identifier is parsedProgramWhen looking for data in the scope chain, you can find the desired data at the top of the scope chain, and the efficiency naturally increases.
This statement can solve many performance problems:Set cache to save data in local variables.
Reprinted please indicate the source:
Refer:
- High-performance JavaScript-zakas)
- Understanding JavaScript closures
- Ruan Yifeng, learning JavaScript closures
- Network Miscellaneous