In-depth understanding of JavaScript scope series third - declaration hoisting (hoisting)

previous words

It is generally believed that javascript code is executed line by line from top to bottom. But actually this is not quite true, mainly because of the existence of declaration hoisting.

Variable declaration hoisting

a = 2;
var a;
console.log(a);

Intuitively, it will be considered undefined, because var a is declared after a = 2;, the variable may be reassigned, because it will be given the default value of undefined. However, the real output is 2.
Even if the code below is like this, it will still output 2.

var a = 2;
var a;
console.log(a);

Because according to the principle of the compiler in the compilation phase: the compiler looks up whether the scope already has a variable named a that exists in the collection of the same scope. If so, the compiler ignores the declaration and continues to compile; otherwise it asks the scope to declare a new variable in the current set of scopes, named a.

Given the above output, it might be thought that the following code snippet would also output 2. But in fact, the real output is undefined.
The reason all of this goes against the look and feel is the compiler's compilation process.

console.log( a ) ;
var a  =  2 ;

The first article covered the internals of scope, where the engine compiles javascript code before interpreting it. Part of the compilation phase is to find all the declarations and associate them with the appropriate scope.

All declarations including variables and functions are processed first before any code is executed.

var a = 2;

This code snippet actually consists of two operations: var a and a = 2;
the first definition declaration is made by the compiler during the compilation phase. The second assignment is left in place waiting for the engine to execute during the execution phase.

//对变量a的声明提升到最上面后,再执行代码时,控制台输出2
var a;
a = 2 ;
console.log(a);

Declaration hoisting is "moved" to the top of the current scope from where they appear in the code, a process called hoisting

[Note]: Each scope will be promoted.

console.log(a);
var a = 0;
function fn(){
    console.log(b);
    var b = 1;
    function test(){
        console.log(c);
        var c = 2;
    }
    test();
}
fn();
//变量声明提升后,变成下面这样
var a ;
console.log(a);
a = 0;
function fn(){
    var b;
    console.log(b);
    b = 1;
    function test(){
        var c ;
        console.log(c);
        c = 2;
    }
    test();
}
fn();

In fact, the real improvement should be as follows, but in order to facilitate understanding, the above expression is more acceptable.

//变量声明提升后,变成下面这样
var a ;
function fn(){
    var b;
    function test(){
        var c ;
        console.log(c);
        c = 2;
    }
    console.log(b);
    b = 1;
    test();
}
console.log(a);
a = 0;
fn();

function declaration hoisting

There are two types of declarations: variable declarations and function declarations. Not only variable declarations can be promoted, but function declarations can also be promoted.

foo();
function foo(){
    console.log(1);//1
}

The above code snippet can output 1 to the console because the foo() function declaration is hoisted.

function foo(){
    console.log(1);
}
foo();

Function declarations are hoisted, but function expressions are not.

foo();
var foo = function(){
    console.log(1);//TypeError: foo is not a function
}

The variable identifier foo in the above program is hoisted and assigned to the global scope, so foo() will not cause a ReferenceError. However, foo is not assigned a value at this time, and foo() will cause an illegal operation due to a function call to an undefined value, so a TypeError exception will be thrown.

//变量提升后,代码如下所示:
var foo;
foo();
foo = function(){
    console.log(1);
}

Even named function expressions cannot be hoisted.

foo();//TypeError: foo is not a function
var foo = function bar(){
      console.log(1);
};
//声明提升后,代码变为:
var foo;
foo();//TypeError: foo is not a function
foo = function bar(){
      console.log(1);
};

The name of a function expression can only be used inside the function body, not outside the function body.


var foo = function bar(){
    console.log(1);
};
bar();//TypeError: bar is not a undefined

function coverage

Both function declarations and variable declarations are hoisted, however, function declarations override variable declarations.

var a;
function a(){}
console.log(a);//'function a(){}' //函数名代表整个函数

However, if there is an assignment operation to the variable, the final value is the value of the variable.

var a=1;
function a(){}
console.log(a);//1
var a;
function a(){};
console.log(a);//'function a(){}'
a = 1;
console.log(a);//1

[Notes] The repeated declaration of variables is useless, but the repeated declaration of functions will overwrite the previous declaration (whether it is a variable or a function declaration [not very understandable])
[1]: The repeated declaration of variables is useless

var a = 1;
var a;
console.log(a);//1

[2]: Since function declaration promotion is better than variable declaration promotion [override variable declaration or promotion to the front of the variable], the variable declaration has no effect.

var a;
function a(){
    console.log(1);
}
a();//1

[3]: The following function declaration will overwrite the previous function declaration.

a();//2
function a(){
    console.log(1);
}
function a(){
    console.log(2);
}

Therefore, duplicate declarations in the same scope should be avoided.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325640567&siteId=291194637