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.
The content of this article 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. I have a Chinese/English electronic version here, if necessary, contact QQ317665171 or qqmail.
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 ), this function saves all objects in the scope when it is created, and the linked list formed by this scope set 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):
Function add (num1, num2 ){
Var sum = num1 + num2;
Return sum;
}
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 the local variable and the global variable have the same name, the local variable is used instead of the global variable, 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 have encountered before. Of course, if you still have questions, I hope you can post the code and 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:
Function initUI (){
With (document) {// avoid!
Var bd = body,
Links = getElementsByTagName (""),
I = 0,
Len = links. length;
While (I <len ){
Update (links [I ++]);
}
GetElementById ("go-btn"). onclick = function (){
Start ();
};
Bd. className = "active ";
} // EOf
}
When the code is executed to with, the scope chain of Execution Context is changed temporarily, and a new variable object is inserted to the top of the scope chain, this variable object contains all the attributes of the object specified. If you access the local variable of the function in with, the newly inserted variable Object will be traversed and then searched in Activation Object until it is found, at this time, the search efficiency will be reduced (this is also why many people say they do not want to use with, I think as long as they try to not affect the performance, after all, accessing the attributes of objects specified by the with statement is still very fast. If you want to know about the performance, you can follow my next blog, "javascript data access performance".)
Figure 3
When a code error occurs in the try block in a try catch statement, it automatically jumps into the catch Block and inserts the exception object specified by the catch statement to the top of the scope chain, however, catch has a feature that after the catch clause is executed, the scope chain will return to the original state.
Closure:
- A"Closure"Is an expression (typically a function) that can have free varuables together with an environment that binds those variables (that" closes "the expression). -- ECMA262
- A closure is an expression (generally a function) that has a free variable and an environment bound to these variables (the environment is "closed ). -- Li songfeng
- A closure is a function that can read internal variables of other functions. -- Ruan Yifeng
For the classic topic of closure, the previous experts on the Internet have already done a lot of detailed explanations. If I explain it too much, it seems that some of my classes have made an axe. However, I have different understandings of closure, the surface may be different.
Here we will analyze the methods and features of the closure from the perspective of scope.
We all know that closures allow us to access data in the scope outside the closure function scope (To put it simply, closure allows us to access data of functions outside the closure function .), This is a very powerful function of closures. Many complex web applications are related to this feature, such as creating closed namespaces and retaining external function execution environments.
Let's take a closure example:
function assignEvents(){
var id = "xdi9592";
document.getElementById("save-btn").onclick = function(event){
saveDocument(id);
};
}
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:
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 parser looks for data in the scope chain, it can directly find the desired data at the top of the scope chain, which naturally improves the efficiency.
This statement can solve many performance problems:Set cache to save data in local variables.
Reprinted please indicate the source:
Refer:
- 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, the closure function is parsed to create 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.
4. 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,
- High-performance javascript-Zakas)
- Understanding javascript closures
- Ruan Yifeng, learning javascript closures
- Network Miscellaneous
From sunny