Deep understanding of JavaScript declaration hoisting

Get into the habit of writing together! This is the 11th day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the details of the event .


This article was first published on my blog .

1 Introduction

The JS engine will precompile before executing JavaScript. During JS precompilation, varvariable declarations and functionfunction declarations in JS will be advanced to the front of the current scope.

Traditional arts, let's first look at a question to see if you have fully grasped the declaration promotion: what
is the correct output of the following code? (The answer is the best, if you are not very clear, it is recommended to continue reading.)

var foo = function () {
    console.log(100);
}
function foo() {
    console.log(200);
}
foo();
复制代码

2. Declarative boost

Before the JS engine interprets and runs the code, it will first process all declarations in any code, including variables and functions, and put them at the forefront of the current scope, while the remaining assignment statements stay in place and wait for execution. The declaration is brought forward from the original position to the front of the current scope, so it is called declaration hoisting (Hoisting) .

2.1 Variable declaration hoisting

// 输出 undefined
console.log(a);
var a = 'hello';
复制代码

According to variable promotion, the variable is declared athrough var, this declaration var awill be advanced, and the variable a = 'hello'will stay in place. So the code is equivalent to:

var a;
// 输出 undefined
console.log(a);
a = 'hello';
复制代码

Note that variable declarations are hoisted, but variable initializations are not.

// 输出 undefined
console.log(a);
var a;
a = 'hello';
复制代码

Every scope in the code is hoisted.

console.log(a); // undefined
var a = 100;
function fn() {
    console.log(b); // undefined
    var b = 200;
    function gn() {
        console.log(c); // undefined
        var c = 300;
    }
    gn();
}
fn();
复制代码

The output of the above code, after being boosted, is equivalent to:

var a;
console.log(a); // undefined
a = 100;
function fn() {
    var b;
    console.log(b); // undefined
    b = 200;
    function gn() {
        var c;
        console.log(c); // undefined
        c =  300;
    }
    gn();
}
fn();
复制代码

2.2 Function declaration hoisting

functionDeclaring a function also has the declaration hoisting feature, and the function declaration (including the function body) is brought to the front of the current scope.

// 输出 hello
foo();
function foo() {
    console.log('hello');
}
复制代码

The above code is equivalent to:

function foo() {
    console.log('hello');
}
// 输出 hello
foo();
复制代码

Note that vardeclared function expressions do not have function declaration hoisting. For example the following anonymous function expression:

// 输出 undefined
console.log(foo);
foo(); //TypeError: foo is not a function
var foo = function () {
    console.log('hello');
}
复制代码

The above code is equivalent to:

var foo;
console.log(foo); // 输出 undefined
foo(); // TypeError: foo is not a function
foo = function () {
    console.log('hello');
};
复制代码

For named function expressions, there is also no declaration of hoisting.

console.log(foo); // undefined
foo(); // TypeError: foo is not a function
var foo = function bar() {
    console.log('hello');
}
复制代码

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

var bar = 10;
var foo = function bar() {
    bar = 30; // (3)
    console.log(bar); // (1)
}
foo();
console.log(bar); // (2)
bar(); // (4)
复制代码

In the above code, (1) outputs:

ƒ bar() {
    bar = 32;
    console.log(bar);
}
复制代码

Output at (2): 10, the code at (3) is invalid, and an error is reported at (4).

The letand constdo not have the declaration hoisting feature.

3. Function declaration takes precedence

If there are declarations of variables and functions with the same name in the code, both will be promoted, and finally the function declaration will override the variable declaration.

// 输出:foo () {}
console.log(foo);
var foo = 100;
function foo () {}
复制代码

The above code is equivalent to:

function foo() {};
var foo; // 变量提升被函数声明提升覆盖,变量重复声明无效
console.log(foo); // foo() {}
foo = 100;
复制代码

But if there is an assignment statement console.logbefore , it foois the value of the variable.

var foo = 100;
function foo () {};
console.log(foo); // 100
复制代码

Note that repeated declarations of variables are useless, but repeated declarations of functions override previous declarations .

  • Repeated declarations of variables are useless
    var foo = 100;
    var foo;
    console.log(foo); // 100
    复制代码
  • Duplicate declarations of functions overwrite previous declarations
    foo(); // 200
    function foo () {
        console.log(100);
    }
    function foo () {
        console.log(200);
    }
    复制代码
  • Function declaration hoisting takes precedence over variable declaration hoisting
    foo(); // 200
    var foo = 100;
    function foo() {
        console.log(200);
    }
    复制代码
    The above code is equivalent to:
    function foo() {
        console.log(200);
    }
    var foo;
    foo(); // 200,函数声明提升优先于变量声明提升,变量声明无效
    foo = 100;
    复制代码

4. Some cases

Case 1:

var bar = 100;
function foo () {
    console.log(bar); // (1)
    var bar = 200;
    console.log(bar); // (2)
}
复制代码

will output at (1) and output undefinedat (2) 200. According to the variable promotion principle, the above code is equivalent to:

var bar = 100;
function foo () {
    var bar;
    console.log(bar); // undefined
    bar = 200;
    console.log(bar); // 200
}
复制代码

Case 2:

var foo = function () {
    console.log(100);
}
function foo() {
    console.log(200);
}
foo();
复制代码

The above code will output 100, according to the function declaration promotion priority principle , the code can be converted to:

function foo() {
    console.log(200);
}
var foo;
foo = function () {
    console.log(100);
} // 原函数被变量赋值覆盖,此时 foo 函数体为后面赋值的。
foo(); // 100
复制代码

Reference in this article

Guess you like

Origin juejin.im/post/7085328890788315150