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(预解析) 

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值