javascript的作用域链变量提升及预解析

Posted 傻了吧爷会飞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javascript的作用域链变量提升及预解析相关的知识,希望对你有一定的参考价值。

一、javascript的作用域链

  • 如果函数中还有函数,或者块级作用域又嵌套块级作用域,那么在这个作用域中就又可以诞生一个作用域,这样的嵌套作用域形成了链状的结果就是作用域链。
  • 查找原则:从上到下,从里到外,即先找局部作用域里找,然后子对象会一级一级向上寻找所有父对象的变量。
<script>
        /* 函数作用域链 */
        var num=1;//0级作用域
        function test(){
            var num=10;//1级作用域
            function func(){
                var num=89;//2级作用域
                function func1(){
                    var str='orange';//3级作用域
                    console.log(num);//89  现在当前作用域中找,若当前作用域中无法找到就去上一级作用域中找
                }
                func1();
            }
            func();
        }
        test();


        /* 块级作用域链 */
        let arr=[3,8,0]//0级作用域
        {
            let arr=[10,7,3];//1级作用域
            {
                console.log(arr);//[10, 7, 3]  2级作用域
                {
                    console.log(num);//1        3级作用域  
                }
            }
        }
    </script>


二、变量提升及预解析

1、变量提升

  • JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。
  • var变量提升时,只将var定义的变量提升到此作用域的最顶部,不提升赋值。
  • 函数声明提升只提升函数到此作用域的最顶部,不直接调用。(注意:函数提升分为函数表达式和函数声明,只有函数声明才会提升)
  • 先提升var,再提升函数。

2、预解析

  • 预解析规则: 对于script是自上而下进行解析,对于函数是由里到外进行解析。
  • 预解析规则:JavaScript “预解析”过程中,遇到重名的内容,只保留一个。(重名变量或重名函数,保留最后的一个。变量和函数重名,只保留函数。
<script>
        console.log(num);//undefined
        var num=10;
        var num=8;
        console.log(num);//8 (重名变量或重名函数,只保留最后一个)
        /* 
        预解析:
        var num;// 把变量的声明提升到当前作用域的最顶部
        console.log(num);
        num=10;
        num=8;
        console.log(num)
        */
    </script>
<script>
        var num=10;
        function test(){
            console.log(num);//undefined
            var num=56;
            function func(){
                console.log(num);//56    func函数作用域中若找不到num,往上一层作用域找
            }
            func();
        }
        test();
        /* 
        预解析:
        var num;
        function test(){
            var num;
            console.log(num);
            num=56;
            function func(){
                console.log(num);//56  
            }
            func();
        }
        num=10;
        test();
        */
    </script>

注意1:var和function同名时,function的优先级高于var(变量和函数重名,只保留函数)。

<script>
        console.log(num);//打印num函数
        var num=10;
        function num(){
            console.log('hello');
        }
        console.log(num);//10
        /* 
        预解析:
        // var和function同名时,function的优先级高于var。
        function num(){
            console.log('hello');
        }
        var num;
        console.log(num);
        num=10;
        console.log(num);
        */
    </script>

注意2:变量以函数的参数传入时,变量在函数作用域中变成了局部变量 。

<script>
        var a=4;
        function test(a){
            console.log(a);//4
            var a=7;
            var b=6;
            function func(){
                return a+b
            }
            console.log(func());//13
        };
        test(a);
        /* 
        预解析:
        var a;
        a=4;
        function test(a){
            var a;
            var b;
            a=4;
            console.log(a);//4
            a=7;
            b=6;
            function func(){
                return a+b //7+6
            }
            console.log(func());//13
        };
        test(a);
        */
    </script>
<script>
        var a=20;
        var b=12;
        function test(a){
            console.log(a);//20
            a=45;
            b=23;
        }
        test(a);
        console.log(a);//20
        console.log(b);//23

        /* 
        预解析:
        var a;
        var b;
        function test(a){//a以函数的参数传入时,a在函数作用域中变成了局部变量
            var a;
            a=20;
            console.log(a);
            a=45;
            b=23;//b还是全局变量
        }
        a=20;
        b=12;
        test(a);
        console.log(a);//20
        console.log(b);//23
        */
    </script>

注意3:如果函数赋值给变量时,只有变量预解析,函数不会预解析。

<script>
        console.log(test);//undefined
        test();//test is not a function
        var test=function(){
            //函数表达式
        }
        /* 
        预解析:
        var test;
        console.log(test);
        test();
        test=function(){
            //函数表达式
        }
        */
    </script>

 注意4:let定义的变量不会预解析,只会遵守JavaScript的“从上到下”的运行规则。

<script>
        var a=20;
        test();
        function test(){
            console.log(a);//undefined
            console.log(b);// 报错
            var a=3;
            let b=100;
        }
        /* 
        预解析:
        var a;
        function test(){
            var a;
            console.log(a);
            console.log(b);
            a=3;
            let b=100; //let定义的变量不会预解析,只会遵守JavaScript的“从上到下”的运行规则。
        }
        a=20;
        test();
        */
    </script>

参考菜鸟教程 https://www.runoob.com/js/js-scope.html 

学习的课程:李南江的前端课程 (他的简书https://www.jianshu.com/p/c73f5124d69f

学习的文章:https://blog.csdn.net/weixin_42614080/article/details/90114780(预解析) 

以上是关于javascript的作用域链变量提升及预解析的主要内容,如果未能解决你的问题,请参考以下文章

javascript的作用域链变量提升及预解析

JavaScript函数函数进阶作用域及预解析

JavaScript 作用域作用域链变量提升

JavaScript 作用域作用域链变量提升

JavaScript作用域:全局作用域局部作用域块级作用域作用域链变量提升

JS高级. 05 词法作用域变量名提升作用域链闭包