词法作用域2 - 函数作用域和块作用域

Posted wydumn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了词法作用域2 - 函数作用域和块作用域相关的知识,希望对你有一定的参考价值。

  1. 隐藏内部实现
    1. 最小授权原则 -- 最小限度地暴露必要内容。
    2. 所以不会将变量和函数都声明在全局作用域中
      1. function doSomething(a) {
            b = a + doSomethingElse(a * 2);
        
            console.log(b * 3);
        }
        
        function doSomethingElse(a) {
            return a - 1;
        }
        
        var b;
        
        doSomething(2);    // 15

        变量b和函数doSomethingElse()是函数doSomething()的私有内容,外部作用域可以访问到是危险的,下面将私有内容隐藏在函数内部。

      2. function doSomething(a) {
            var b;
        
            function doSomethingElse(a) {
                return a - 1;
            }
        
            b = a + doSomethingElse(a * 2);
        
            console.log(b * 3);
        }
    3. 隐藏的作用
      1. 避免变量覆盖
        1. 第三方库中将需要暴露的功能加入命名空间
        2. 模块
  2. 函数作用域
    1. var c = ‘hey‘;
      
      function bo() {
          var c = ‘hi‘;
          console.log(c);
      
      }
      
      bo();    // hi
      console.log( c );    // hey

       上述代码的问题

      1. 函数bo()‘污染’了所在作用域,因为是一个具名函数

      2. 只能显式地通过函数名调用函数
    2. 期待能够不要函数的名字,并且没有名字也可以运行
      1. var c = ‘hey‘;
        
        (function bo() {
            var c = ‘hi‘;
            console.log(c);  // hi
        })();
        
        console.log(c);  // hey
      2. 区分函数和函数表达式就是看function关键字是否是声明的第一个词。
      3. 上面代码中,function前还有一个 ‘(‘ ,所以是函数表达式
      4. 所以 (function bo(){ .. }) 只能在 .. 中访问,不能被外部作用域访问。变量名bo被隐藏在自身中,最小授权
    3. 匿名和具名
      1. 匿名函数表达式的缺点
        1. 调试时,栈内并没有函数名
        2. 函数表达式递归时,只能用arguments.callee
        3. 可读性降低
      2. 行内函数表达式 -- 具名
      3. setTimeout( function() {
            console.log(‘等1秒!‘);
        }, 1000 );
        
        
        // 行内函数表达式
        setTimeout( function timeoutHandler() {
            console.log(‘等1秒!‘);
        }, 1000 );
    4. Immediately Invoked Function Expression --- 立即执行函数表达式
      1. var word = ‘hi‘;
        
        (function IIFE() {
            var word = ‘hey‘;
            console.log(word);    // hey
        })();
        
        console.log( word );    // hi

         函数IIFE中第一个括号将函数定义为函数表达式,第二个括号使函数立即运行

        下面是IIFE的另一种形式,将第二个括号写入第一个括号里
      2. var word = ‘hi‘;
        
        ( function IIFE() {
            var word = ‘hey‘;
            console.log(word);    // hey
        }() );
        
        console.log( word );    // hi
      3. 作用
        1. 匿名函数表达式
        2. 作为主调函数,传递参数
          1. var say = ‘hi‘;
            
            (function IIFE(global){
                var say = ‘hey‘;
                console.log(say);    // hey
                console.log(global.say);    // hi
            }(window));
            
            console.log(say);    // hi
          2. 避免undefined的默认值被错误覆盖导致的异常(我还没见过)
            undefined = true;
            
            (function IIFE( undefined ) {
                var a;
                if (a === undefined) {
                    console.log(‘Undefined is safe here!‘);
                }
            })();
          3. 倒置代码的运行顺序
            say = ‘hi‘;
            
            (function run1(func) {
                func(window);
            })( function run2(global) {
                var say = ‘hey‘;
                console.log(say);    // hey
                console.log(global.say);    // hi
            });

             函数run2在函数run1执行之后当作参数传进去

  3. 块作用域
    1. 为什么引入块作用域?
      var a = true;
      
      if (a) {
        var b = a * 2;
        console.log( b );   
      }

       尽管变量b声明在块作用域内,但是var声明的变量不具有块作用域的特性,所以变量b被绑定在全局作用域内,污染了全局作用域,破坏了最小暴露原则。

      • 块作用域可以将隐藏在函数内的信息扩展为块中隐藏的信息。所以能提高代码的可维护性。
    2. with的块作用域(不懂)
    3. try...catch中catch的作用域,没遇到过,先放着

以上是关于词法作用域2 - 函数作用域和块作用域的主要内容,如果未能解决你的问题,请参考以下文章

js 函数作用域, 块级作用域和词法作用域

JavaScript的作用域

JavaScript全局作用域函数作用域和块级作用域的区别

《你不知道的javascript》——词法/函数/块作用域

《你不知道的javascript》函数作用域和块作用域

《你不知道的javascript》函数作用域和块作用域