javascript中的作用域

js的作用域,按工作模型,可以分为:词法作用域和动态作用域。按类型,可以分为:函数作用域和块作用域。

一、什么是词法作用域

词法作用域是定义在词法阶段的作用域。换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的。在编译阶段进行静态确定的形式。

/*
               全局作用域有:foo
            foo的作用域有: a b bar
            bar的作用域有: c
       */
       function foo(a){
               let b = a * 2function bar(c){
                   console.log(a,b,c);
               }
               bar( b * 3 );
       }
       foo(2);         //2,4,12

 

二、什么是动态作用域

在运行时才动态确定的形式。关注函数从何处调用。不过JavaScript并不具有动态作用域。都是词法作用域。但javascript中的this机制却很像动态作用域。

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

        let a = 2;

        function bar(){
            let a = 3;
            foo();
        }

        bar();        //2    (这里是词法作用域) 调用foo() 是找不到变量a, 向上一级作用域(这里是全局作用域)继续查找,然后找到了a = 2;

 

三、函数作用域

特点:词法作用域意味着作用域是由书写时函数声明的位置来决定的。

function foo(a){
            let b = 2;
            function bar(){
                console.log("foo bar");     //foo bar
                //同样在bar ( . . ) 内部也可以被访问
                console.log(a);     //1
            }
            let c = 3;
            //但是,这些标识符(a、b、c、f oo 和bar)在f oo( . . ) 的内部都是可以被访问的,
            console.log(a,b,c,bar);
            bar();
        }

        foo(1);//1 2 3 f bar(){console.log('foo bar'); console.log(a);}
        // 标识符 a、b、c 和 bar 都附属于 f oo( . . ) 的作用域气泡,因此无法从 f oo( . . ) 的外部对它们进行访问
        //console.log(a);   //a is not defined
        //console.log(b);   //b is not defined
        //console.log(c);   //c is not defined
        //console.dir(bar);   //bar is not defined

优点:(1)能隐藏内部实现,最小限度地暴露必要内容,符合软件设计的原则。(2)规避冲突(常用的做法有:声明一个独特的对象作为给库的命名空间;使用模块管理)

//对外暴露的不必要的变量:b 和 bar
        let b;
        function foo(a){
          b = bar(a+2);
          return b+a;
        }
        function bar(a){
          return a*2;  
        }
        console.dir(foo(11));   //37


        //改写成:
        function foo(a){
            function bar(a){
              return a*2;  
            }
            let b = bar(a+2);
            return b+a;
        }
        console.dir(foo(11));   //37

缺点:(1)本身函数名暴露了,可以使用立即执行函数表达式。

//对外暴露了函数名
        function foo(a){
          console.log(a);
        }
        foo(2);

        //改成立即执行函数表达式
        (function foo(a){
          console.log(a);
        })(2);
        foo(2);     //foo is not defined

 

四、块作用域

优点:防止变量外泄;垃圾回收

形成过程:ES3开始,只能通过with 和 try/catch 来生成块作用域;ES6提出了 let 和 const 关键字,来得到块作用域

// 有效 ES6环境下的代码转换成能在ES6之前环境运行的代码转换工具的原理:
        try{
            throw undefined;
        }catch(b){
            b = 2;
            console.log(b);        //2
        }
        console.log(b);     //b is not defined

        //无效,外界还是能访问
        if(true){
            var a = 1;
            console.log(a);     //1
        }
        console.log(a);     //1

        //改为es6的写法     有效
        if(true){
            let a = 1;
            console.log(a);     //1
        }
        console.log(a);     //a is not defined

 

注:var 与 let 和 const 的区别除了块作用域外,还有声明的提升

// var声明提升
        console.log(a);     //undefined
        var a = 1;
        console.log(a);     //1

        //相当于
        var a;
        console.log(a);     //undefined
        a = 1;
        console.log(a);     //1

        
        console.log(b);     //报错:b is not defined
        let b = 2;
        console.log(b);

 

posted @ 2021-02-23 18:15  拉布拉多~  阅读(180)  评论(0编辑  收藏  举报