作用域

# 作用域

# 预编译

预编译特征

  • 任何没有声明的变量直接赋值,那么这个变量将直接归 window 所有。 暗示全局
  • 全局声明的变量 会直接归属到 window 下

预编译流程:

  • 创建 AO 对象 (AO --> 函数执行期上下文)
  • 找形参和变量声明,将变量和形参名作为 AO 属性名,值为 undefined
  • 将实参值和形参统一
  • 在函数体里面找函数声明,值赋予函数体。

预编译决定了函数将要运行时声明的状态(var、function)

function test(a,b){
  console.log(a) // function a(){}
  var a;
  console.log(b) // 2
  function a(){}
  a = 234;
  console.log(a); // 234
  var b =123;
  console.log(c);  // Refference Error c is not define
}

test(1,2);

如果预编译放到全局中会形成另一个 GO 对象。 规则相同。

# 作用域

在预编译阶段会创建出 AO 和 GO (Action Object、Global Object)这叫做函数执行期上下文。发生在函数即将执行之前,如果多次执行一个函数,就会创建多个函数执行期上下文。 [[Scope]] 即作用域,里面存储了执行期的上下文 作用域链:[[Scope]] 中所存储的执行期上下文对象的集合,这个集合呈链式链接,

        function a() {
            var a = 1;
            function b() {
                var b = 2;
                function c() {
                    var c = 3;
                }
                c()
            }
            b()
        }

        a()

每个函数都可以看做是一个对象

// example a doing 
a --> [[Scope]] --> 
[
  AO -> {
    arguments:{},
    this: window,
    a:1,
    b:function (){}
  },
  GO -> {
    window,
    document,
    a:function (){},
  }
]

逐行解析,作用域的在执行期间作用域顶部始终是自己的执行上下文,

a-- > define-- > [[Scope]]-- > [0: GO]
a-- > doing-- > [[Scope]]-- > [0: a - AO, 1: GO]

b-- > define-- > [[Scope]]-- > [0: a - AO, 1: GO]
b-- > doing-- > [[Scope]]-- > [0: b - AO, 1: a - AO, 2: GO]

c-- > define-- > [[Scope]]-- > [0: b - AO, 1: a - AO, 2: GO]
c-- > doing-- > [[Scope]]-- > [0: c - AO, 1: b - AO, 2: a - AO, 3: GO]

当函数执行完毕,会销毁自身的作用域,将自身的顶部作用域出栈回退回 define 阶段 如果函数再次执行将会再次创建执行期上下文。