# javascript执行上下文

当javascript执行一段代码时,会创建对应的执行上下文

对于每个执行上下文,都有三个重要属性:

  1. 变量对象(Variable object,VO)
  2. 作用域链(Scope chain)
  3. this

# 变量对象

变量对象是与执行上下文相关的数据作用域,存储了在上下文中定义的变量和函数声明

# 全局上下文中变量对象

全局上下文中的变量对象就是全局对象
全局对象是由 Object 构造函数实例化的一个对象,因此它预定义了一大堆函数和属性,例如使用Math.max(),其实就是使用了全局对象。
全局对象可以使用this引用,在客户端javascript中以window引用。

# 函数上下文中变量对象

  1. 函数上下文的变量对象初始化只包括 Arguments 对象

  2. 在进入执行上下文时会给变量对象添加形参、函数声明、变量声明等初始的属性值

  3. 在代码执行阶段,会再次修改变量对象的属性值

# javascript 作用域链

当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的链表就叫做作用域链

# 函数创建

函数有一个内部属性 [[scope]],当函数创建的时候,就会保存所有父变量对象到其中,你可以理解 [[scope]] 就是所有父变量对象的层级链,但是注意:[[scope]] 并不代表完整的作用域链!
举个例子:

function foo() {
    function bar() {
        ...
    }
}

函数创建时,各自的[[scope]]为:

foo.[[scope]] = [
  globalContext.VO
];

bar.[[scope]] = [
    fooContext.AO,
    globalContext.VO
];

# 函数激活

当函数激活时,进入函数上下文,创建 VO/AO 后,就会将活动对象添加到作用链的前端。

这时候执行上下文的作用域链,我们命名为 Scope:

Scope = [AO].concat([[Scope]]); 至此,作用域链创建完毕。

# 执行上下文栈

执行到一个函数的时候,就会进行准备工作,这里的“准备工作”,让我们用个更专业一点的说法,就叫做"执行上下文(execution contexts)"。
JavaScript 引擎创建了执行上下文栈(Execution context stack,ECS)来管理执行上下文。
当执行一个函数的时候,就会创建一个执行上下文,并且压入执行上下文栈,当函数执行完毕的时候,就会将函数的执行上下文从栈中弹出

# 小结

执行上下文就是创建一段代码后,所出现的类似编译后的执行规则,代码执行通过执行上下文来执行代码。