In this article, I'll delve deeper into the most basic parts of JavaScript-the execution context (execution contexts). After reading this article, you should be aware of what the interpreter did, why the functions and variables can be used before the declaration, and how their values are determined.
1. ec-execution environment or execution context
Whenever the controller arrives at the ECMAScript executable code, the controller enters an execution context (the concept of a tall one).
In JavaScript, EC is divided into three types:
- Global-Level code-this is the default code runtime environment, and once the code is loaded, the engine first enters the environment.
- Code at the function level – when executing a function, run the code in the body of the function.
- Eval Code – code that runs within the Eval function.
The EC establishment is divided into two phases: the execution context (creation phase) and the execution phase (activation/execution code).
- Enter the context stage : Occurs when a function call is made, but before the execution of the specific code (for example, before a function parameter is materialized)
- Creating a scope chain (scope Chain)
- Create variables, functions, and parameters.
- The value of the "this".
- Execute code Phase :
- Assigning values to variables
- Function reference
- Interpret/execute other code.
We can consider the EC as an object.
EC={ VO:{/* 函数中的arguments对象, 参数, 内部的变量以及函数声明 */}, this:{}, /* VO以及所有父执行上下文中的VO */}}
Now let's look at a code example that contains the global and function context:
In a very simple example, we have a global context that is circled by a purple border and three different function contexts that have been framed by green, blue, and orange respectively. Only the global context (the variable) can be accessed by any other context.
You can have any number of function contexts, each time the function is called to create a new context, a private scope is created, and any variables declared inside the function cannot be accessed directly outside the scope of the current function. In the example above, the function can access the variable declaration outside the current context, but the internal variable/function declaration cannot be accessed outside the context. Why is this happening? How exactly is the code being interpreted?
2. ecs-execution Context Stack
The execution context of a series of activities logically forms a stack. The bottom of the stack is always the global context, and the top of the stack is the current (active) execution context. When switching between different execution contexts (exiting and entering a new execution context), the stack is modified (by means of a stack or a fallback).
Press Stack : Global ec-> local ec1-> local ec2-> current EC
out of Stack : Global ec<-local ec1<-local ec2<-current EC
We can represent the environment stack in the form of an array:
ECS=[局部EC,全局EC];
Each time the controller enters a function (even if the function is called recursively or as a constructor), the operation of the stack will occur. The process is similar to the push and pop operations of a JavaScript array.
The JavaScript interpreter in the browser is implemented as a single thread. This means that only one thing can happen at a time, and other lines or events will be placed in the queue called the execution stack. The following figure is an abstract view of the single-line stacks:
We already know that when the browser loads your script for the first time, it will go into the global execution context by default. If, you call a function in your global code, your program's timing will go into the called function and wear a new execution context and press the newly created context into the top of the execution stack.
If you call other functions inside the current function, the same thing will be staged here. The execution of the code enters an intrinsic function, creates a new execution context, and pushes it to the top of the execution stack. The browser will always execute the execution context at the top of the stack, and once the current context function is executed, it will be ejected from the top of the stack and given contextual control to the current stack. The following example shows the execution stack invocation procedure for a recursive function:
(function foo(i) { if (i === 3) { return; } else { foo(++i); }}(0));
This code calls itself three times and adds one to the value of I each time. Each time the Foo function is called, a new execution context is created. Once the context is executed, it pops up from the top of the stack and returns control to the following context until only the global context can be left.
There are 5 key points to remember about the execution stack (call stack):
- Single Thread.
- Synchronous execution.
- A global context.
- Unrestricted function context.
- Each time a function is called to create a new execution context, including calling itself.
3. Vo-Variable Object
Each EC corresponds to a Variable object VO, and all variables and functions defined in the EC are stored in their corresponding VO.
Vo is divided into the global context Vo (Global object, Universal object, which we usually call global objects) and the AO of the function context.
VO: { // 上下文中的数据 ( 函数形参(function arguments), 函数声明(FD),变量声明(var))}
1. When entering the execution context, the initialization process of VO is as follows:
The formal parameter of the function (when entering the function execution context)--a property of the variable object whose property name is the name of the formal parameter, the value of which is the value of the argument, and for the parameter not passed, its value is undefined;
function declaration (functiondeclaration, FD)--a property of the variable object whose property name and value are created by the function object, and if the variable object already contains a property of the same name, replace its value;
Variable declaration (var,variabledeclaration)--a property of a variable object whose property name is the variable name and whose value is undefined; if the variable name and the function name already declared or the parameter name of the function are the same, the existing property will not be affected.
Note: The process is sequential.
2. When executing the code phase, some of the property undefined values in VO will be determined.
4. AO Activity Object
In the context of the execution of a function, VO is not directly accessible. It mainly plays the role of being called the active object (activation objects) (abbreviation: AO).
How to understand this sentence, that is, when the EC environment is a function, we are visiting AO, not VO.
VO(functionContext) === AO;
The AO is created when entering the execution context of the function and initializes an arguments property for the object with the value of the arguments object.
AO = { arguments: { callee:, length:, //函数传参参数值 }};
The form of FD can only be as follows:
function f(){}
When the function is called Executioncontextobj is created, but before the actual function is executed. This is the first stage we mentioned above, the creation phase. At this stage, the interpreter scans the arguments passed to the function or arguments, the local function declaration and the local variable declaration, and creates the Executioncontextobj object. The result of the scan completes the creation of the variable object.
The internal execution sequence is as follows:
1. Find the code that invokes the function.
2. Before executing the function code, create the execution context first.
3. Enter the creation stage:
- Initialize the scope chain:
- To create a variable object:
- Creates a arguments object, examines the context, initializes the parameter name and value, and creates a copy of the reference.
- function declaration for the scan context: For each function found, create a property on the variable object (exactly the name of the function), which has a reference to the function in memory. If the name of the function already exists, the reference pointer is overridden.
- The variable declaration of the sweep surface context: For each variable declared, create a property on the variable object--the name of the variable, and initialize the value of the variable to undefined, if the name of the variable exists in the variable object, no action will be taken and the scan continues.
- Find the value of "This" inside the context.
4. Activation/Code Execution phase:
Runs/interprets the function code on the current context and executes the value of the assigned variable along with the line of code.
Example
1. Concrete examples
function foo(i) { var a = ‘hello‘; varfunction privateB() { }; function c() { }}foo(22);
When you call Foo (22), the creation state looks like this:
fooExecutionContext = { ... }, variableObject: { arguments: { 022, 1 }, 22, function c() a: undefined, b: undefined }, ... }}
As you can see, the creation State is responsible for processing the names of the defined properties, not assigning them specific values, and handling the formal parameters/arguments. Once the creation phase is complete, the execution flow enters the function and the activation/code execution phase, looking at what it looks like after the function executes:
fooExecutionContext = { ... }, variableObject: { arguments: { 022, 1 }, 22, function c() a: ‘hello‘, function privateB() }, ... }}
2. Vo Example:
// functionvar10// 1020;function x() {// 20
When you enter the execution context,
ECObject={ VO:{ x:<referenceto"x"> }};
When executing code:
ECObject={ VO:{ x:20 //与函数x同名,替换掉,先是10,后变成20 }};
For the above procedure, we explain in detail.
When the context is entered, Vo is filled with the function declaration, and at the same stage, the variable declares "x", but, as mentioned earlier, the variable declaration is after the function declaration and the function parameter, and the variable declaration does not conflict with the function declaration and function parameter of the same name that already exists. Therefore, at the stage of entering the context, Vo fills in the following form:
VO = {};VO[‘x‘] = <引用了函数声明‘x‘>// 发现var x = 10;// 如果函数“x”还未定义// 则 "x" 为undefined, 但是,在我们的例子中// 变量声明并不会影响同名的函数值VO[‘x‘] = <值不受影响,仍是函数>
The execution code phase, VO is modified as follows:
VO[‘x‘10;VO[‘x‘20;
As shown in the following example, the variable is stored in VO in the context stage (so, although the else code block is never executed, and "B" is still in Vo)
if (true) { var1else { var2//1//undefinednot"b is not defined"
3. AO Example:
function test(a, b) { var10; function d() {} varfunction _e() {}; (function x() {});}test(10// call
When entering the execution context of test (10), its AO is:
testEC={ AO:{ arguments:{ callee:test length:1, 0:10 }, a:10, c:undefined, d:<referenceto"d">, e:undefined }};
Thus, in the establishment phase, VO in addition to arguments, function declarations, and parameters are given specific property values, the other variable properties default is undefined. The function expression does not affect VO, so (function X () {}) does not exist in VO.
When the test (10) is executed , its AO is:
testEC={ AO:{ arguments:{ callee:test, length:1, 0:10 }, a:10, c:10, d:<referenceto"d">, e:<referenceto"e"> }};
Visible, only at this stage, the variable property is assigned a specific value.
5. Lifting (hoisting) decryption
In the previous JavaScript item, the variables and function declarations were promoted to the top of the function scope. However, no one explained the details of why this happened, and learned the new knowledge about how the interpreter created the active object, and it's easy to see why. Look at the following example:
(function() { console.log(typeof// 函数指针 console.log(typeof// undefined var foo = ‘hello‘, function() { return ‘world‘; }; function foo() { return ‘hello‘; }}());
We can answer the following questions:
1. Why can we access it before the Foo declaration?
If we follow the creation phase, we know that the variable has been created during the activation/code execution phase. So foo is already defined in the active object before the function starts executing.
2. Foo is declared two times, why does Foo appear as a function instead of a undefined or a string?
Although Foo is declared two times, we know that from the Create phase function has been created in the active object, this process occurs before the variable is created, and if the property name already exists on the active object, we only update the reference.
Therefore, the reference to the Foo () function is first created in the active object, and when we interpret the Var foo, we see that the Foo attribute name already exists, so the code does nothing and continues execution.
3. Why is the value of bar undefined?
Bar is actually a variable, but the value of the variable is a function, and we know that the variable was created in the creation phase but they are initialized to undefined.
Copyright NOTICE: This article is the original article, reproduced please specify: http://blog.csdn.net/i10630226
You don't know the javascript--item19 execution context (execution context)