Compilation principle

We know that JavaScript is a compiled language, and it’s not pre-compiled. Compilation of JS takes place in a very short time before the code executes. The source code in a program goes through three stages of word segmentation, parsing, and code generation before execution, which we collectively call compilation.

  • This stage can be called either word segmentation or lexical analysis. The distinction between the two is subtle and difficult to understand, and it doesn’t hurt that I don’t know the difference. In this process the source code composed of strings is decomposed into meaningful code blocks that compute lexical units. Var a = 2 is broken down into lexical units var, a, =, and 2.
  • The task of the parsing/parsing process is to replace the lexical unit flow generated in the word segmentation phase with a hierarchical nested tree representing the syntax structure of the program. This number is known as the AST (Abstract Syntax Tree).

  • Code generation Our computer can only recognize binary, and the process of converting an AST into binary executable code is code generation.

scope

React we often use state to indicate component state. The word state is personally important to a programming language. Without the word state, programs can perform simple tasks, but it limits their flexibility. In programming languages, we use variables to represent states. Almost any programming language has the ability to store, access, and modify variable values, and it is this ability to store and access variables that brings state to the program. Now that we have variables, we need to think about where do we put them and how do we find them when we need them? At this point we need to design a good set of rules to store and access variables. A scope is a set of rules for storing and accessing variables. There are three scopes:

  • Global scope
  • Function scope
  • Block-level scope

These three scopes will be explained in more detail later when we summarize closures. After all, closures and scopes are inseparable from the precompilation process. To better understand scopes, we also need to look at engines and compilers.

  • The engine is responsible for the compilation and execution of the whole JS program from beginning to end.
  • One of the compiler engine’s best friends, responsible for parsing and code generation.

When we see var a = 2 we think of this as a declaration, but the engine thinks there are two declarations, one handled by the compiler at compile time and one handled by the engine at run time. So let’s factor var a = 2. The compiler first breaks down this line of code into lexical units, which it then parses into a tree structure. Finally, executable code is generated.

In fact, the compiler does the following.

1. If var a is encountered, the compiler will ask if the variable a already exists in the current scope. If so, the compiler will ignore the variable declaration and continue compiling. If there is no change, a variable named A is declared in the current scope. 2. The compiler then generates the run-time code for the engine to perform the assignment of a = 2. At execution time, the engine looks for variable A in the current scope. If variable A is found, the engine uses it, and if not, the engine continues to look for it.

LHS and RHS(Left/Right Hand Search)

These two methods are how the engine looks up variables. LHS and RHS meaning “left or right side of assignment” does not mean “= left or right side of assignment operator”. Assignment operations take several other forms, so conceptually they are best understood as “Who is the target of an assignment operation (LHS)” and “who is the source of the assignment operation (RHS)”

  • Both LHS and RHS occur when the engine queries variables
  • LHS variable assignment or write to memory (save text file to hard disk)
  • RHS variables look up or read from content imagine opening a text file from a hard disk

Features:

  • Is queried in all scopes
  • In strict mode, the engine will ReferenceError if the desired variable is not found
  • In non-strict mode, LHS automatically creates a global variable
  • After a successful query, improper operations on variables will generate TypeError, such as the following code
var a = 2;
a();
Copy the code


function foo(a) {
    var b = a; 
    return a + b; 
}
var c = foo(2); 
Copy the code

LHS has 3 places: C =.. ; A = 2(implicit variable assignment), b =.. RHS has 4: Foo (2.. , = a; A and B in return

The scope chain

Nesting of scopes occurs when a block or function is nested within another block or function. Therefore, when a variable cannot be found in the current scope, the engine continues to look in the outer nested scope until it finds the change or reaches the outermost scope (global scope). Scope-chain lookup is closely related to precompilation.

Precompiled four-step:

  1. Create an AO Object (Activation Object, execution context, scope)
  2. Find the parameter and variable declarations and use the variable and parameter names as AO property names with the value undefined
  3. Unify argument values and parameters
  4. Find the function declaration inside the function body and assign the value to the function body
function fn(a) {
    console.log(a);
    var a = 123;
    console.log(a);
    function a() {}
    console.log(a);
    var b = function () {};
    console.log(b);
    function d() {}
}
fn(1);
Copy the code

AO {a: undefined, b: undefined,} 3. AO {a: 1, b: undefined,} 4. AO {a: function a(){}, b: undefined,d: function d() {}}

functionfn(a) { console.log(a); // In the AO at this time isfunction a(){} var a = 123; Var a = 123; // var a = 123; // var a = 123; / / 123function a() {}; // Precompile has already been performed, no need to execute console.log(a); Var a = 123 var b = 123function() {}; // var b has been executed. Run b =function(){},AO b from undefined to anonymous function console.log(b); //function() {}
    function d} fn(1);} fn(1);Copy the code

Function a(){},123,123,function(){}

Let’s do another one

function a(age) {
    console.log(age);
    var age = 20;
    console.log(age);
    function age() {

    }
    console.log(age);
}
a(18);
Copy the code
  1. AO{}
  2. AO{age:undefined}
  3. AO{age:18}
  4. AO{age:function age(){}}

After the precompiled execution is complete, the engine starts executing the code

functiona(age) { console.log(age); //function age(){} var age = 20; Var age = 20, AO{age:function age(){}} becomes AO{age:20} console.log(age); / / 20function age() {}// Console.log (age) has been executed during precompilation; // age is still 20} a(18);Copy the code

Function age(){},20,20