概述

执行上下文是当前JavaScript代码被解析和执行时所在环境的抽象概念

执行上下文的类型

执行上下文总共有三种类型

  • 全局执行上下文 只有一个,浏览器的全局对象是window,this指向这个全局对象
  • 函数执行上下文 只有在函数被调用时才会被创建,每次调用函数都会创建一个新的执行上下文
  • Eval函数执行上下文 eval函数中的代码,很少用而且不建议使用

执行栈

执行栈,也叫调用栈,具有 LIFO(后进先出)结构,用于存储在代码执行期间创建的所有执行上下文。
首次运行JS代码时,会创建一个全局执行上下文并Push到当前的执行栈中。每当发生函数调用,引擎都会为该函数创建一个新的函数执行上下文并Push到当前执行栈的栈顶。
根据执行栈LIFO规则,当栈顶函数运行完成后,其对应的函数执行上下文将会从执行栈中Pop出,上下文控制权将移到当前执行栈的下一个执行上下文。

执行上下文的创建

执行上下文分两个阶段创建

  1. 创建阶段
  2. 执行阶段

创建阶段

1、确定 this 的值,也被称为 This Binding。
2、LexicalEnvironment(词法环境) 组件被创建。词法环境又有如下两个部分

  • 环境记录:存储变量和函数声明的具***置
  • 对外部环境的引用:可以访问外部词法环境

3、VariableEnvironment(变量环境) 组件被创建。
变量环境也是一个词法环境,因此它具有上面定义的词法环境的所有属性。在 ES6 中,词法 环境和 变量 环境的区别在于前者用于存储函数声明和变量( let 和 const )绑定,而后者仅用于存储变量( var )绑定。

执行上下文栈

JS引擎会创建很多的执行上下文,所以JS引擎创建了执行上下文栈(Execution context stack,ECS)来管理执行上下文
当 JavaScript 初始化的时候会向执行上下文栈压入一个全局执行上下文,我们用 globalContext 表示它,并且只有当整个应用程序结束的时候,执行栈才会被清空,所以程序结束之前, 执行栈最底部永远有个 globalContext。

ECStack = [        // 使用数组模拟栈
    globalContext
];

函数上下文

在函数上下文中,用活动对象(activation object, AO)来表示变量对象。
活动对象和变量对象的区别在于
1、变量对象(VO)是规范上或者是JS引擎上实现的,并不能在JS环境中直接访问。
2、当进入到一个执行上下文后,这个变量对象才会被激活,所以叫活动对象(AO),这时候活动对象上的各种属性才能被访问。
调用函数时,会为其创建一个Arguments对象,并自动初始化局部变量arguments,指代该Arguments对象。所有作为参数传入的值都会成为Arguments对象的数组元素。