【 introduction 】

This article briefly summarizes an understanding of the concept of enhancement in JavaScript learning. Friends with different opinions can leave a message in the comment section, we communicate and discuss together.

[text]

As we all know, in the traditional compiled language running process, source code will undergo “lexical analysis”, “syntax analysis”, “code generation” three steps, collectively known as compilation. In JavaScript, there is a concept called precompilation, and precompilation is divided into global precompilation, which happens when the page is loaded, and function precompilation, which happens just before the function is executed. In fact, the term precompiled here is not quite accurate, as variable hosting, the enhancement of var and function, mentioned in JavaScript’s Secret Garden, describes this process. But it’s helpful to call this process precompilation. Let’s get down to business.

Function precompilation

Global precompilation, divided into four steps, occurs before the function body is executed, which we call tetralogy here.

  1. Creating an AO Object

  2. Find the parameter and variable declarations as the attribute names of AO objects with the value undefined

  3. Unify arguments and parameters

  4. Find the function declaration in the function body and assign the function name as the property name of the AO object

It might be hard for you to understand, but that doesn’t matter, because I’m also haha, so let’s go into the code and analyze it

` var a = 1
    function fn(a) {
      var a = 2
      function a() {}
      var b = a
      console.log(a); // 2
    }
    fn(3)
`
Copy the code

Now let’s go through the code in four steps. ① First create an AO object

` AO
 {

 }`
Copy the code

② Now let’s look for parameters and variable declarations. We find a and B and assign them to undefined

>  AO: {
>        a: undefined 
>        b: undefined 
>      }
Copy the code

③ Then unify the parameters

>  
>   AO: {
>          a: 3
>          b: undefined 
>       }
Copy the code

Function a(); function a(); function a();

>  
>   AO: {
>        a: function a() {}  
>        b: undefined 
>      }
Copy the code

At this point, the precompilation process of the function body is finished, and the function body gets the value in the AO before it is run. Then it runs normally, the overlay of the overlay. Here’s an example for you to practice:

> function fn(a) {
>       console.log(a); // function() {}
>       var a = 123;
>       console.log(a); // 123
>       function a() {}
>       console.log(a); // 123
>       var b = function() {}
>       console.log(b); // function() {}
>       function d() {}
>       var d = a
>       console.log(d); // 123
>     }
>     fn(1)
Copy the code

What is the output of console.log(a) in the second line? Function () {} is the output function() {} is the output function() {} is the output function() {}.

>  AO: {
>        a: undefined  1  function() {}   ,
>        b: undefined  function() {},
>        d: undefined  function () {}   
>      }
> 
Copy the code

Some people might think that this can be solved by variable promotion, but we need to know that a few lines of code you can probably figure out, when you have dozens of lines of code in front of you, this approach is more efficient.

Global precompilation

Global precompilation is a three-step process, but be aware that if there is a function in the process, we also precompile the function.

  1. Create a GO object
  2. Find the variable declaration as the property name of the GO object, and assign the value to undefined
  3. Find the function declaration in the global, and assign the function name as the property name of the GO object, and the value to the function body
var global = 100
function fn() {
  console.log(global); // undefined
  global = 200
  console.log(global); // 200
  var global = 300
}
fn()
Copy the code

The method is basically the same as the function precompiled above, except that there is no procedure to find the parameters and arguments, and the parameters are unified. Here we directly paste the result, because the string of code has functions, so we also precompiled it

`
GO: {
      global:undefined 
      fn: function() {}
    }

AO: {
      global: undefined
    }`
Copy the code

The third line of console.log(global) will output undefined, which is what precompilation tells us, so let’s change it a little bit. Replace the var global = 100 in the first line with global = 100. Now let’s think, what is the GO object in the global precompilation now? console.log(global); What does it output? Here, let’s see the results:

` GO: {
          global:undefined 
          fn: function() {}
        }
        
   console.log(global); // undefined
Copy the code

Yeah, it still has the same value. The second step in global precompilation is to look for variable declarations. Global = 100 = 100; global = 100 = 100; At this point, we will introduce a new concept, RHS query and LHS query

RHS and LHS query

Var a=2 for analysis;

Let’s take a look at the compilation process. When our compiler takes this program, it breaks it down into lexical units, which it then parses into a tree structure called an abstract syntax tree, or AST for short. The next step is to turn the AST into machine instructions, that is, into executable code. So when our engine executes this code, it first looks for variable A to determine whether it has been declared. The search requires scope assistance, but the way the engine performs the search affects the final result.

Engine lookup is divided into RHS and LHS, R and L mean right and left, that is, LHS query will be performed on the left side of the variable assignment operation, and RSH query will be performed on the right side. An RHS query is the same as simply looking up the value of a variable to get a value of something. An LHS query is an attempt to find the container of the variable itself to assign a value to it. Here is a code example to make it easier to understand

`console.log(a); `Copy the code

The statement here needs to find the value of A, so it’s an RHS lookup

`a=2`
Copy the code

We don’t really care what a=2 is, we just want to find a target for the =2 assignment, okay

As FAR as I can remember, the source of direct assignment operations like console, where finding a value is usually an RHS reference, and when there is an = sign, where finding the target of the assignment is usually an LHS reference.

Both RHS look-ups and LHS look-ups start at the currently executing scope, and if they do not find the desired identifier in the current scope, they step up to the upper scope to find the target identifier until they reach the global scope, at which point they stop whether or not they find it.

RHS differs from LHS in that a ReferenceError is raised if an RHS reference is unsuccessful. LHS implicitly creates a global variable, meaning that if a in a=2 is not declared in scope, it creates a global variable when LHS is referenced. No guns, no guns, we build our own.

So let’s go back to the code at this point

global = 100
function fn() {
   console.log(global); // undefined
   global = 200
   console.log(global); // 200
   var global = 300
}
fn()
Copy the code

At this time, global was not declared, and we made a LHS reference to it. When we did not find the target identifier in the global scope, we automatically created a global variable implicitly, which can be interpreted as the implementation of var global=100, so when we performed the global precompile trilogy, You can find the variable declaration for Global. This explains why two different lines of code have the same result.

Note: Ideas from JavaScript you Don’t Know