Variable promotion and function declaration promotion

In the previous section, we looked at the execution stack and execution context in JS in detail, and briefly explained why variable promotion occurs. In this section, we’ll take a closer look at variable declarations, function declarations, variable promotion, and function promotion. Finally, we’ll look at class declarations and how lets and const work.

First, let’s look at a question:

console.log(a);
function a() {
    console.log('fa')}console.log(b);
var b = 'b';
Copy the code

What will be the print result after the above code is executed?

ƒ a() {console.log(‘fa’)} and undefined

Why did this happen? First, we need to look at the preprocessing mechanism in JavaScript.

Preprocessing mechanism

Before executing JavaScript, statements in scripts, modules, and function bodies are preprocessed. Var, function declaration, class, const, and let statements are preprocessed to determine the meaning of the variables.

Var declaration — variable promotion

Var declarations always apply at the level of script, module, and function body. In the preprocessing phase, you don’t care about the assignment part, just declare the variable in the current scope.

/ / sample
console.log(b);
var b = 'b';
Copy the code

In the above code, JavaScript preprocesses var b = ‘b’ before execution. The global environment declares a variable b with the value of undefined, so the first line of console.log(b) prints undefined.

Function expression that executes immediately (IIFE)

Because JavaScript had no lets and const in the early days, var was the only way to use it, and because VAR was penetrable beyond scripts and function bodies, the public invented the use of “instant-executed function expressions (IIFE)” to generate scopes.

// Add 20 div elements to the document and bind click events to print their ordinals
for(var i = 0; i < 20; i ++) {
    void function(i){
        var div = document.createElement("div");
        div.innerHTML = i;
        div.onclick = function(){
            console.log(i);
        }
        document.body.appendChild(div);
    }(i);
}
Copy the code

We use IIFE to construct scopes within the loop, and each loop produces a new environment record so that each div has access to I in the environment.

If we don’t use IIFE:


for(var i = 0; i < 20; i ++) {
    var div = document.createElement("div");
    div.innerHTML = i;
    div.onclick = function(){
        console.log(i);
    }
    document.body.appendChild(div);
}
Copy the code

The result of this code will be to print 20 for each div, because there is only one I globally, and after the loop, I becomes 20.

With the let keyword, let can be used to declare block-level scopes, so we can do without IIFE.

Function declarations — Function declarations are promoted

Globally (scripts, modules, and function bodies), the function declaration behaves like var, except that it not only adds a variable to the scope, but also assigns a value to it.

/ / sample
console.log(a);
function a() {
    console.log('fa')}Copy the code

Function a (){… function a (){… ƒ a() {console.log(‘fa’)}} with an A variable with the value ƒ a() {console.log(‘fa’)}.

Note: The situation is a bit more complicated when a function declaration appears in statements such as if. It still applies to the script, module, and function body levels. During the preprocessing phase, variables are still generated, but they are no longer assigned in advance:

/ / sample
console.log(foo);
if(true) {
    function foo(){}}Copy the code

This code gets undefined and throws an error if there is no function declaration. This indicates that function still works in the preprocessing stage. Variables are generated in scope, but no assignment is generated. Assignment occurs in the execution stage. Functions that appear in statements such as if will still be preempted in the scope created by if, resulting in assignment effects.

console.log(foo);
if(true) {
    console.log(foo);
    function foo(){}}Copy the code

This code gets undefined and ƒ foo(){}.

The class declaration

If the class name is used before the class declaration, an error will be raised.

/ / sample
console.log(C);
class C {}Copy the code

The above code raises an Uncaught ReferenceError: C is not defined, which behaves as if the class is not preprocessed, but it is not.

Class declarations are also preprocessed. They create variables in scope and throw errors when asked to access them. Class declarations do not penetrate if structures, so they are only declared in the global context.

/ / sample
const a = 2;
if(true) {console.log(a); / / wrong
    class a {}}Copy the code

This code globally declares a variable of A with a value of 2, but in the function block, it makes a class declaration again. The class declaration is preprocessed, and instead of accessing the externally declared A variable in the scope of if, the class declaration is called class A, so an error is thrown.

Let, const

Let and const are both declarations of variables. They are very similar in nature and quite different from var declarations.

Let and const declarations appear to be executed, but they are actually preprocessed. External variables cannot be accessed if there are declarations in the current scope.

Note: Let, const, and class are declared in a similar way

/ / sample
const a = 2;
if(true) {console.log(a); / / wrong
    const a = 1;   
}
Copy the code

In the if scope, the const declaration is preprocessed, and the JS engine already knows that the following code will declare variable A, thus denying us access to variable A in the outer scope.

Bootleg classroom

Let’s start with a quick question: if there are both function declarations and variable declarations in the same scope, what are their priorities?

console.log(a);
var a = 'varA';
console.log(a);
function a() {
    console.log('funA');
}
a();
Copy the code

ƒ a() {console.log(‘funA’); }, varA, Uncaught TypeError: A is not a function.

ƒ a() {console.log(‘funA’); }; When we continue to the second line, because we have already declared a, we will assign varA to the variable a, which will be varA. So the third line will print varA; Function a(){} statement was declared to have been executed, so the function a(){} statement was skipped. Uncaught TypeError: A is not a function. Uncaught TypeError: A is not a function.

If both function and variable declarations exist in the same scope, there are only two things to remember to solve the problem:

  • Function declarations take precedence over var declarations
  • Multiple function declarations with the same name exist in the same scope, and the latter one replaces the previous one

Here are some interesting topics for you to better understand:

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

foo();

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

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

foo();

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

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

foo();

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

foo();
Copy the code

conclusion

In this section, we introduce variable declaration enhancement, function declaration enhancement, class declaration and let/const declaration in detail. We will move on to other CORE JS knowledge.

I am how to celebrate more than years, if the article has helped you, I hope you can point a thumbs-up, thank you!

If you have any questions, please discuss them in the comments section.