1. 词法阶段
    1. 词法化
      1. 对源代码中的字符进行检查
    2. 词法作用域
      1. 就是写代码时将变量和块作用域写在哪里决定
    3. 作用域查找会在找到第一个匹配的标识符时停止
      1. 所以,重名标识符会有overriding
    4. 作用域始终从运行时所处的最内部作用域开始
      1. 逐级向外,沿着作用域链
    5. 综上,运行时,在最内部作用域开始搜寻变量,找不到沿着作用域链向外查找,找到第一个与之匹配的标识符,OK
  2. 改变词法作用域
    1. eval
      • function foo(str, a) {
             eval(str);
             console.log(a, b);
         }
        
         var b = 2;
         foo("var b = 3;", 1);    // 1, 3
    2. 严格模式下的eval没有效果
      • function foo(str) {
            "use strict";
            eval( str );
            console.log( a );    // ReferenceError: a is not defined
        }
        foo( "var a = 2" );
      • 严格模式下,eval在运行时有自己的词法作用域
    3. eval(..)可以将包含声明语句的代码字符串插入,修改运行时的词法作用域
      1. with
    4. var obj = {
          a: 2,
          b: 3
      };
      
      function fo(obj) {
          with (obj) {
              b  = 5;
          }
      }
      
      var o = {
          b: 33
      };
      
      var p = {
          a: 23
      };
      
      fo(o);
      console.log(o.b);    // 33
      
      fo(p);
      console.log(p.b);    // undefined
    5. 对象o有属性;,对象p没有属性b,不会创建该属性
    6. with语句将一个对象的引用作为作用域来处理,将对象的属性当作作用域中的标识符,创建了一个新的运行时词法作用域
      1. eval和with使引擎在编译时对作用域的优化无效,所以会导致运行变慢。
  3. 函数作用域和块作用域
    1. 隐藏内部实现

    2. 最小授权原则(最小暴露原则)

      1. 最小限度地暴露必要内容。
    3. 所以变量和函数不会都声明在全局作用域中

      1. function doSomething(a) {
            b = a + doSomethingElse(a * 2);
        
            console.log(b * 3);
        }
        
        function doSomethingElse(a) {
            return a - 1;
        }
        
        var b;
        
        doSomething(2);    // 15
      2. 变量b和函数doSomethingElse()是函数doSomething()的私有内容,外部作用域可以访问到是危险的,下面将私有内容隐藏在函数内部。

      3. function doSomething(a) {
            var b;
        
            function doSomethingElse(a) {
                return a - 1;
            }
        
            b = a + doSomethingElse(a * 2);
        
            console.log(b * 3);
        }
    4. 隐藏的好处

02-01 16:51