What does the interpreter do next when the function is added to the Call Stack and the execution context for that function is created?
- Creation stage:
(1) Create a Variable Object: (2) establish a Scope chain; (3) determine the point of this in the function
- Execution phase:
① Variable assignment ② function reference ③ execute other code
When the execution phase is complete, the execution context is off the stack and the memory is reclaimed.
1. Variable Object
Normally, we write code that includes defining many variables and functions. How does the browser’s built-in interpreter work when given JS code?
The interpreter first needs to find the definitions of these variables and functions, and it will first generate variable objects when the execution context is created.
In a function environment, for example, when a function is called, it is pushed onto the function call stack and is at the top of the stack. At this point, we first enter the execution context creation phase, which consists of the following three parts:
- Create the Arguments object for the function. Check the parameters in the current context and establish the properties and property values under the object. Without an argument, the property value is undefined.
- All function declarations inside this function. Is a function declared using the function keyword. Create a property in the variable object with the function name. The property value is a reference to the memory address where the function resides. If the property of the function name already exists, it will be overwritten by the new reference.
- All variable declarations inside this function. Each time a variable declaration is found, a property is created in the variable object with the name of the variable and the value of the property is undefined. If the variable name is the same as the declared formal parameter or function, the variable declaration does not affect the existing attributes.
The process of creating variable objects
Activation Object 2
Again, the functional environment is the main scenario. The properties in the variable object are not accessible until the execution phase. After the execution phase, the variable Object becomes an active Object, and its properties can be accessed, and the code is executed.
Note that”become“Is the word. It is indicated in the context of function executionVariable Object 和Activation ObjectIt’s the same object, they just exist in different lifecycles.
3.JS Hosting mechanism
1. Variable improvement
Here’s an example:
var str = 'global';
function fn() {
console.log(str);
var str = 'local';
console.log(str);
}
fn();
Copy the code
The output
undefined
'local'
Copy the code
We know that variable promotion is promoting the declaration part to the top of the function level scope. Here’s how the interpreter handles this code:
var str = 'global';
function fn() { / / fn functions
var str; // STR is promoted here in the declaration part of the fn scope. The default value is undefined
console.log(str); // Read the value of STR in the fn scope, and get undefined
str = 'local'; // STR is assigned to the fn scope
console.log(str); // Take STR again and get the value 'local'
}
fn();
Copy the code
Var STR = ‘local’ in the second line of the fn function is broken into two parts:
- Var STR; In the context creation phase of fn, the variable object is generated with only the name of the variable, and the declaration part of the code is raised to the top of fn’s scope. The value of STR is undefined by default
- ② Assignment part: STR = ‘local’;
Inside fn, the assignment to STR is already the third line. Assignment occurs during the execution phase of the function execution context, which completes the transformation of the variable object into the live object, determines the value of the variable’s property and references to the function declaration inside the function fn. At this point, we also enter the part of the code to execute, the first print STR output undefined, the second output ‘local’.
2. Function promotion
Function promotion is the same as variable promotion, which is promoted to the top of the current scope, but there are some differences: let’s look at an example:
console.log(fn1); // [Function: fn1]
fn1(); // fn1
console.log(fn2); // undefined
fn2(); // Uncaught TypeError: fn2 is not a function
function fn1() { // Declare the function
console.log('fn1');
}
var fn2 = function(){ // Function expression
console.log('fn2');
};
Copy the code
- Function fn1 is called before the declaration, and the printed result can be obtained, and the call succeeds successfully, indicating that function fn1 is promoted.
- An error will be reported when calling fn2, indicating that the function expression will not be promoted. If you want to call fn2, the calling statement should be written after the function expression that declares fn2.
That’s one, but the point is the second example:
var str = 'global';
function fn() {
str = 'local';
console.log(str);
return;
function str() {};
}
fn();
console.log(str);
Copy the code
The output
'local'
'global'
Copy the code
When this code is processed, the execution context enters the execution phase, completes variable assignments and function references, and is ready to execute the code, the code looks like this:
var str = 'global';
function fn() {
var str = function () {};
str = 'local';
console.log(str);
return;
}
fn();
console.log(str);
Copy the code
Var STR = function () {} Then the second line of STR = ‘local’ assigns STR to ‘local’, and the third line prints ‘local’.
Function promotion takes precedence over variable promotion because:
This happens from left to right, so obviously the second assignment to the function comes before the third assignment to the variable.
To conclude: describe the function context lifecycle in a relatively abstract piece of code (which is almost the processing logic of the interpreter) : first, the creation phase:
// The function fn performs the creation phase of the context
fnExecutionContext = { // fn Execution context
VariableObject: {}, // Variable object
ScopeChain: {}, // Scope chains. We'll discuss scopes and scope chains in a later article}...// the variableObject that handles the fn execution contextVariableObject = { args: {... },// Suppose the interpreter initializes a variable object with a list of fn arguments defined by args
_fn: <_fn reference> // _fn indicates a function definition in the execution context of fn, and <_fn reference> indicates an address reference
str: undefined // STR represents the definition of a variable in the execution context of fn
}
Copy the code
Then comes the execution phase:
// Convert the variable object into an active object
Variable Object => Activation Object
...
// Complete the assignment to the variableObjectVariableObject = { args: {... },// Suppose fn passes arguments and args has some specific values
_fn: <_fn reference> // <_fn reference> function () {}
str: 'local' // the STR variable has a value of 'local'
this: window // Assume that fn is defined in the window, i.e. in the global execution environment
}
Copy the code