JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的。JavaScript解析器执行JavaScript代码的时候,分为两个过程:预解析过程和代码执行过程
预解析过程:

  1. 把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
  2. 把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。
  3. 函数声明和变量声明都会置顶,但是变量声明位于函数声明之后

    变量的提升

    1. <script>
    2. var num = 10;
    3. function test1(){
    4. console.log(num);
    5. var num = 20;
    6. }
    7. test1();
    8. /*
    9. js解析器会将上面的代码进行变量的提升:只会提升变量的声明,不会提升赋值
    10. var num = 10;
    11. function test1(){
    12. var num;
    13. console.log(num);
    14. num = 20;
    15. }
    16. test1();
    17. */
    18. </script>

    image.png

    函数的提升

     <script>
         test2();
         function test2(){
             console.log("test2执行了");
         }
    
         /*
         js解析器也会对函数的声明进行提升,提升到当前script标签的最前面
         function test2(){
             console.log("test2执行了");
         }
         test2();
         */
     </script>
    

    image.png

    隐式全局变量的注意点

    f2();
    console.log(c);
    console.log(b);
    console.log(a);
    function f2() {
    var a = b = c = 9;
    console.log(a);
    console.log(b);
    console.log(c);
    }
    等效于
    function f2() {
    var a;  //局部变量
    a = 9;  
    b = 9;  //隐式全局变量
    c = 9;  //隐式全局变量
    console.log(a);  //9
    console.log(b);  //9
    console.log(c);  //9
    }
    f2();
    console.log(c);  //9
    console.log(b);  //9
    console.log(a);  //undefined   因为a是局部变量
    

隐式全局变量的进一步说明

var a = 18;
b = 10;
console.log(b);
delete b;
console.log(b);   //此处会报错,原因隐式全局变量的声明是可以通过delete关键字删除的。
                  //删除之后就没有b的定义,无法console.log()
delete a; //全局变量是不可以delete的,此处delete无效
console.log(a);

image.png

函数提升在前,变量提升在后

var a = 3;
function a(){
    console.log(10);
}   
console.log(a);
a();

image.png

//提升的时候,变量声明位于函数之后
等效于:

function a(){
    console.log(10)
}         //前
var a;    //后
a = 3;
console.log(a);  //3
a();  //not function

函数中出现和全局变量同名的变量 以及if中出现和全局变量同名的变量的处理方式

var tmp = new Date();
function f(){
    console.log(tmp);
    if(false){
        var tmp = "hello";
    }
}
f();

image.png
等效为:

var tmp = new Date();
function f(){
    var tmp;
    console.log(tmp);
    if(false){
        tmp = "hello";
    }
}
f();

因为变量申明是在任意代码执行前处理的,在代码区中任意地方申明变量和在最开始(最上面)的地方申明是一样的。也就是说,看起来一个变量可以在申明之前被使用!这种行为就是所谓的“hoisting”,也就是变量提升,看起来就像变量的申明被自动移动到了函数或全局代码的最顶上。
注意:仅仅是申明提升了,定义并不会被提升。

函数中出现和全局变量同名的变量 以及if中出现和全局变量同名的变量的处理方式

var x = 1;
console.log(x);
if(true){
    var x = 2;
    console.log(x);
}
console.log(x);

image.png

等效为

var x = 1;
console.log(x);
if(true){
    x = 2;
    console.log(x);
}
console.log(x);

js的var变量只有全局作用域和函数作用域两种,且申明会被提升,因此实际上x只会在最顶上开始的地方申明一次,var x=2的申明会被忽略,仅用于赋值。也就是说上面的代码实际上跟下面是一致的。

匿名函数不存在预解析的问题

f1();//-----报错
var f1=function () {
    console.log(a);
    var a=10;
};

image.png

案例

    <script>
        test3();
        //console.log("a=" + a);
        console.log("b=" + b);
        console.log("c=" + c);
        function test3(){
            var a=b=c=9;
            /*
            var a = 9; //局部变量
            b = 9;  //隐式全局变量
            c = 9;  //隐式全局变量
            */
            /*
            console.log(a);
            console.log(b);
            console.log(c);*/
        }
    </script>

image.png

    <script>
        var a = 1;
        function a(){
            console.log("这是a函数");
        }
        console.log(typeof(a));
        //a(); 因为在提升的时候先提升函数,再提升变量,所以此时a就是一个number类型,无法调用函数

        /*
        function a(){
            console.log("这是a函数");
        }
        var a;
        a = 1;
        console.log(typeof(a));
        */
    </script>

image.png

    <script>
        var a = 1;
        var a = function(){
            console.log("这是a函数");
        }
        console.log(typeof(a));
        a();

        /*
        var a;
        a = 1;
        a = function(){
            console.log("这是a函数");
        }
        a();
        */
    </script>

image.png

    <script>
        //全局变量
        var x = 1;
        console.log(x);
        if(true){
            var x = 2;
            console.log(x);
        }
        console.log(x);

        /*
        var x = 1;
        console.log(x);  //1
        if(true){
            x = 2;
            console.log(x);  //2
        }  
        console.log(x);  //2
        */
    </script>

image.png

    <script>
        console.log(f1);
        f1();
        var f1 = function(){
            console.log("这是函数");
        }
        /*
        var f1;
        console.log(f1);
        f1();
        f1 = function(){
            console.log("这是函数");
        }
        */    
    </script>

image.png