JavaScript Execution Mechanism (1) Variable Promotion

Only by understanding the execution context of JavaScript can you better understand the JavaScript language itself, such as variable promotion, scope, and closure. Not only that, but understanding the concepts of execution context and call stack can also help you become a more qualified front-end developer. This time we will talk about variable promotion in js from a context perspective.

Take a look at the following code first:

1
2
3
4
5
6
showName()
console.log(myname)
var myname = 'ray'
function showName() {
Console.log ('function showName executed');
}

For those familiar with js, the output of this code is easy to judge. It will print out separately:

1
2
Function showName is executed
undefined

And if we change the above code to

1
2
3
4
5
showName()
console.log(myname)
function showName() {
Console.log ('function showName executed');
}

At this time, an error of undefined variable will be thrown.

Judging from the execution results of the above two pieces of code, we can draw the following three conclusions.

  • During execution, if an undeclared variable is used, JavaScript execution will report an error.

  • Using a variable before it is defined, there will be no error, but the value of the variable will be undefined, not the value at the time of definition. Using it before a function is defined, there will be no error, and the function executes correctly.

The first conclusion is easy to understand because the variable is not defined, so when executing JavaScript code, the variable cannot be found, so JavaScript will throw an error.

However, the second and third conclusions are quite puzzling:

  • Why can variables and functions be used before they are defined? This seems to indicate that JavaScript code is not executed line by line.

  • ** In the same way, why are the processing results of variables and functions different **? For example, in the execution result above, the showName function used in advance can print the complete result, but the value of the myname variable used in advance is undefined, not the value of “ray” used when defining.

Variable promotion

To explain these two issues, you need to first understand what variable promotion is.

However, before introducing variable promotion, let’s take a look at the following code to see what ** declaration ** and ** assignment ** are in JavaScript.

1
var myname = 'ray'

You can think of this code as consisting of two lines of code.

1
2
Var myname//declaration section
Myname = 'ray'//assignment part

The above is the declaration and assignment of variables, then let’s take a look at the declaration and assignment of function, combined with the following code

1
2
3
4
5
6
7
8

function foo(){
console.log('foo')
}

var bar = function(){
console.log('bar')
}

The first function foo is a complete function declaration, that is, there is no assignment involved; the second function declares the variable bar first, and then assigns function () {console.log (‘bar’) } to bar.

Okay, now that we understand the declaration and assignment operations, we can talk about what variable promotion is. The so-called variable promotion refers to the “behavior” at the beginning of the code that the JavaScript engine promotes the declaration part of the variable and the declaration part of the function during the execution of the JavaScript code. After a variable is hoisted, it will set a default value for the variable, which is familiar to us as undefined.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

/*
* Variable promotion part
*/
//Raise the variable myname to the beginning,
//also assign the value of myname to undefined
var myname = undefined
//raise function showName to the beginning
function showName() {
Console.log ('showName is called');
}

/*
* section of executable code
*/
showName()
console.log(myname)
//Remove the var declaration part and keep the assignment statement
myname = 'ray'

JavaScript execution order

In the literal sense of the concept, “variable promotion” means that the declarations of variables and functions will be physically moved to the front of the code, as we simulated. However, this is not accurate. ** In fact, the position of variable and function declarations in the code does not change, and they are put into memory by the JavaScript engine during the compile phase **. Yes, you heard right, a piece of JavaScript code needs to be compiled by the JavaScript engine before execution. After the compile is completed, it will enter the execution phase.

Compile phase

So what is the relationship between the compile stage and variable promotion? In order to clarify this problem, we still go back and look at the code that simulates variable promotion above. For convenience of introduction, this code can be divided into two parts.

JavaScript 编译执行流程

As can be seen from the above figure, input a piece of code, after compiling, will generate two parts: execution context (Execution context) and executable code.

The execution context is the environment in which JavaScript executes a piece of code. For example, if a function is called, it will enter the execution context of the function and determine the functions used during execution such as this, variables, objects, and functions.

There is a variable environment object (Viriable Environment) in the execution context, which stores the contents of variable promotion, such as the variable myname and function showName in the above code, which are stored in this object.

You can simply think of the variable environment object as the following structure:

1
2
3
VariableEnvironment: 
myname -> undefined,
showName ->function : {console.log(myname)

After understanding the structure of the variable environment object, let’s combine the following code to analyze how to generate the variable environment object.

1
2
3
4
5
6
7

showName()
console.log(myname)
var myname = 'ray'
function showName() {
Console.log ('function showName executed');
}

We can analyze the above code line by line.

  • Lines 1 and 2, since these two lines of code are not declarative operations, the JavaScript engine will not do any processing;

  • Line 3, since this line is declared with var, the JavaScript engine will create a property named myname in the environment object and initialize it with undefined;

  • On line 4, the JavaScript engine finds a function defined by a function, so it stores the function definition on the heap (HEAP), creates a showName property in the environment object, and points the value of that property to the location of the function in the heap (it doesn’t matter if you don’t know about the heap, I’ll cover JavaScript’s execution heap and execution stack in a follow-up article).

Implementation phase

The JavaScript engine starts executing “executable code”, line by line in order. Let’s analyze this execution process line by line:

  • When the showName function is executed, the JavaScript engine starts looking for the function in the variable environment object. Due to the reference of the function in the variable environment object, the JavaScript engine starts executing the function and outputs the result “function showName executed”.

  • Next print “myname” information, the JavaScript engine continues to look for this object in the variable environment object. Since the variable environment has a myname variable and its value is undefined, undefined is output at this time.

  • Next, execute line 3 and assign “ray” to the myname variable. After the assignment, the value of the myname attribute in the variable environment changes to “ray”. The variable environment is as follows:

1
2
3
VariableEnvironment:
myname -> "ray",
showName ->function : {console.log(myname)

Well, the above is the compile and execution process of a piece of code. In fact, the compile stage and the execution stage are very complex, including lexical analysis, syntax analysis, code optimization, code generation, etc