JavaScript includes concepts such as Scope (scope), Scope chain (scope chain), Execute context (execution context), Active Object (active object), Dynamic Scope (dynamic scope), and Closure (closure). To understand these concepts, we analyze them from both static and dynamic aspects.
First, let's write a simple function to make an example:
The code copy is as follows:
function add(num1, num2){
var sum = num1 + num2;
return sum;
}
We define an add function with two formal parameters.
Static aspects:
When creating an add function, the Javascript engine will create a Scope chain of the add function, and this scope chain points to the Global Context. If you use graphical representations, the following figure is shown:
As can be seen from the above figure, when the add function is created, the scope chain has been created, so we can draw a conclusion that the scope chain of the function is created when the function is created, rather than a dynamic run period. Let’s take a look at what happens during the dynamic run.
Dynamic aspects:
When executing the add function, JavaScript will create an Execute context, which contains all the information required during the runtime of the add function. Execute context also has its own Scope chain. When the function is running, the JavaScript engine will first initialize the scope chain of the execution context from the scope chain of the add function, and then the JavaScript engine will create an Active Object, which contains all local variables, parameters, and this and other variables during the function runtime.
If the image is described, what happens during the dynamic runtime of the add function, it can be described in the following figure:
As can be seen from the above figure, the execution context is a dynamic concept. It is created when the function is running. At the same time, the Active Object object is also a dynamic concept. It is referenced by the scope chain of the execution context. Therefore, it can be concluded that both the execution context and the active object are dynamic concepts, and the scope chain of the execution context is initialized by the function scope chain.
The above talks about the scope of function scope and execution context. Let’s talk about the problem of dynamic scope. When JavaScript passes with with statements, try-catch catch clauses, and eval methods, the JavaScript engine will dynamically change the scope of the execution context. Let’s take a look at it with an example:
The code copy is as follows:
function initUI(){
with (document){ //avoid!
var bd = body,
links = getElementsByTagName("a"),
i= 0,
len = links.length;
while(i < len){
update(links[i++]);
}
getElementById("go-btn").onclick = function(){
start();
};
bd.className = "active";
}
When executing the above initUI function, JavaScript will dynamically create a corresponding scope corresponding to the with statement and place it at the front end of the execution context scope chain. The above process can be described vividly through the figure below. The red marked area below shows the scope generated by the with statement.
Finally, let’s take a look at the most mysterious Closure in JavaScript. Closures are actually a function in JavaScript. The closure is created during the function runtime. Let’s take an example to see:
The code copy is as follows:
function assignEvents(){
var id = "xdi9592";
document.getElementById("save-btn").onclick = function(event){
saveDocument(id);
};
}
When the above assignEvents function is executed, a closure will be created, and this closure will refer to the id variable in the scope of assignEvents. If, according to the traditional programming language, id is a variable stored on the stack. When the function is executed, the id disappears, so how can it be referenced again? Obviously, JavaScript adopts another way here. Let’s take a look at how JavaScript implements closures. When executing the assignEvents function, the JavaScript engine will create a scope chain of the execution context of the assignEvents function. This scope chain contains the active objects when the assignEvents is executed. At the same time, the JavaScript engine will also create a closure, and the scope chain of the closure will also refer to the active objects when the assignEvents is executed. In this way, when the assignEvents is executed, although the scope chain of its own execution context no longer refers to the active objects, the closure still refers to the active objects corresponding to the assignEvents runtime, which explains the closure mechanism inside JavaScript. You can use the following figure to describe the situation of the above assignEvents function runtime:
As can be seen from the above, after the assignEvents function is executed, document.getElementById("save-btn").onclick refers to the closure. This way, when the user clicks save-btn, the execution of the closure will be triggered. Let's take a look at the situation when the closure is executed. As mentioned earlier, closures in JavaScript are actually functions, so the situations of closure execution and function execution are consistent. The following figure will vividly describe the closure associated with the above onclick event.
From the above figure, we can see that the JavaScript engine first creates the execution context of the closure, then uses the closure scope chain to initialize the execution context scope chain of the closure, and finally puts the corresponding active object when the closure is executed at the front end of the scope, which further verifies that the closure is a function.