Let’s start with a piece of code

var foo = function () {
    console.log('foo1');
}
foo();  // foo1

var foo = function () {
    console.log('foo2');
}
foo(); // foo2
Copy the code

And then look at this code

function foo() {
    console.log('foo1');
}
foo();  // foo2

function foo() {
    console.log('foo2');
}
foo(); // foo2
Copy the code

The result is two foo2.

Can you tell the order of execution correctly when mixing the above two pieces of code, the variable promotion in the first column and the function promotion in the second column?

Let’s look at a small example of mixing to see more about it

console.log(a) // undefined
var a = 'hello JS'/* Here we have a question to consider. Why doesn't it get an error to print a before we declare a? */ num = 6; num++; var num; Console. log(num) // 7 Consider a question here? Why is assigning a value to an undeclared variable not an errorfunction hoistFunction() {
    foo();
    function foo() {        
        console.log('running... ') } } hoistFunction(); // running... So let's think about a question here, right? Why doesn't Foo get an error when it executesCopy the code

The analysis reason

The S engine performs a “precompile” before executing the code. Precompile simply means to create space in memory for variables and functions. The specific steps are as follows (browser) :

  • The page creates the GO Global Object Object (window Object).
  • Load the first script file
  • After the script is loaded, analyze the syntax.
  • Start precompiling
// The document, navigator, screen, and so on are created when the page is loaded. A: undefined, num: undefined, hoistFunction:function(y){
        foo();
        function foo() {        
        console.log('running... ')}}}Copy the code
  • Explain the execution code (up to the execution function hoistFunction, also known as lexical analysis)
* Create AO Active Object * find the parameter and variable declaration, assign the value of undefined * the argument value to the parameter * find the function declaration, GO/window = {// the variable is initialized with the execution stream a: hello JS, num: 6, // num++ num:7 hoistFunction:function(y){
        foo();
        function foo() {        
        console.log('running... ')}}}Copy the code
  • After the first script file is executed, load the second script file
  • After the second file is loaded, the syntax is analyzed
  • Start precompiling
  • Repeat the precompilation steps….

In the case of reactive power, the preparse mechanism causes a variable or function declaration to move in the case of reactive power, literally, to the starting point of the function or global code (its scope). Let’s take a look at the little example above to get a better understanding.

Console. log(a) // Before execution, the variable is promoted as a property of window, and the value is set to undefined var a ='hello JS'/* JavaScript only promotes the declaration, not the initialization */ num = 6; num++; var num; Console. log(num) // If the variable promotion value is undefined, set num to 6 and then increment => 7function hoistFunction() {
    foo();
    function foo() {        
        console.log('running... ') } } hoistFunction(); // The function declaration is promoted and can be executed before the function bodyCopy the code

Note: there is no real precompilation of JS, var and function enhancements are actually handled during parsing. And JS precompilation is a script file as a block. A script file is precompiled once, rather than “precompiled” after full compilation

What is Hosting?

The engine first compiles JavaScript code before interpreting it, and part of the compilation process is finding all the declarations and associating them with the appropriate scope, which is the heart of lexical scope.

Variable ascension

Variables declared in a global scope are promoted to the top level of the global scope, while variables declared in a function are promoted to the top level of the function scope. Then the initial piece of code is precompiled into


var a;
console.log(a); // undefined
a = "a"; var foo = () => { var a; Console.log (a); // Global variables are overwritten by variables of the same name in the local scope. // undefined a ="a1";
}
foo();
Copy the code

ES6 adds the let and const keywords, which give js a “block” scope. Variables and functions declared with let and const are not promoted, which helps us develop good programming habits.

Function increase

With variable promotion explained above, function promotion is easier to understand, but there are differences between function promotion and variable promotion.


console.log(foo1); // [Function: foo1]
foo1(); // foo1
console.log(foo2); // undefined
foo2(); // TypeError: foo2 is not a function
function foo1 () {
	console.log("foo1");
};
var foo2 = function () {
	console.log("foo2"); } // There may be some questions here. Foo2 will report an error, isn't that also a declaration? // foo2 is a function expression here and will not be promotedCopy the code

Function promotion only improves the function declaration, not the function expression.

Finally, I’ll end with a short example to see if you know anything about function promotion and variable promotion

var a = 1;
function foo() {
    a = 10;
    console.log(a);
    return;
    function a() {};
}
foo();
console.log(a);
Copy the code

Did you get the above little example right?

The code block above, precompiled, can look like this (only inside foo) :

var a = 1; // define a global variable afunction foo() {// First promote the function declarationfunction a() {} to the top of the function scope // thenfunction a() {} is equivalent to var a =function() {}; The final form is var a =function() {}; // Define and assign the local variable a. a = 10; // Changing the value of local variable A does not affect global variable a console.log(a); // Prints the value of local variable A: 10return; } foo(); console.log(a); // Prints the value of global variable A: 1Copy the code