JS执行上下文

执行上下文,即context,也不知道是谁翻译的,很多的文献、书籍用的都是这个词。还记得第一次接触这个词时的惆怅、迷惘、不知所措,扶了扶眼镜,翻开大辞典,仍是翻译成环境比较接地气。JS执行上下文,即JS的执行环境。web

执行环境(Execution Context, EC)

当咱们的代码执行时,会进入到不一样的执行上下文,即不一样的环境。在不一样的环境中,有着不一样的 scope(做用域),代码所能访问到的资源也就不一样。 在 JS 中,执行环境有以下三种状况:浏览器

  • 全局环境bash

    代码默认运行的环境,代码执行时会首先进入全局环境。它是最外围的一个执行环境,根据 ECMAScript 实现所在的宿主环境的不一样,表示全局环境的对象也不同。在 web 浏览器中,全局环境就是 window 对象。全局变量和函数都是做为全局对象 window 的变量和方法来建立的。函数

  • 函数环境post

    函数被调用执行时,所建立的执行环境。ui

  • evalthis

    使用 eval 会进入一个新的执行环境,它的变量对象为全局变量对象或调用者的变量对象。因为 eval 的毒瘤属性,通常不推荐使用,可忽略。spa

某个执行环境中的全部代码执行完毕后,该环境被销毁,保存在环境中的变量和函数也随之销毁。这些变量和函数保存在一个叫作变量对象的对象(variableObject)中,关于变量对象将在变量对象与做用域链一文做详细探讨。线程

执行环境的生命周期

执行环境的生命周期大概分为两个阶段,即建立阶段和执行阶段:翻译

1. 建立阶段

  • 建立做用域链(变量对象+父级执行环境的变量对象)
  • 建立变量对象(包括局部变量、函数以及函数参数)
  • 肯定 this 的指向

由此,一个执行环境能够由包含做用域链、变量对象和 this 指针的对象组成:

executionContextObj = {
  scopeChain: {},
  variableObject: {},
  this: {}
}
复制代码

2. 代码执行阶段

  • 指定变量的值和函数的引用
  • 解释并执行代码

执行环境栈(Execution Context Stack, ECS)

浏览器中的解释器被实现为单线程,同一时间只能处理一个任务,JS 程序中多个执行环境会以栈的方式来处理,这个栈叫作执行栈。栈底永远都是全局环境(窗口关闭时弹出),栈顶就是当前正在执行的环境。前述三种状况都会建立执行环境,执行环境建立时会被压入栈顶,成为一个运行(活动)的环境,位于栈顶的环境执行完毕后就从栈顶弹出,并将环境控制权交给调用者(以前的栈),而调用者继续执行(或激活其余环境),直到它的执行环境结束。ECMAScript 程序中的执行流正是由这个方便的机制控制着。

来看下面的例子:

var firstName = 'snow';

function getName() {
    var lastName = 'John';

    function fullName() {
      var name = lastName + firstName;
      return name;
    }
    var name = fullName();
    return name;
}

getName();
复制代码

其执行栈变化过程以下:

  • 首先,将全局环境压入栈,开始执行代码,

  • 直到遇到getName(),准备调用函数,建立函数 getName 的执行环境,将其压入栈顶并开始执行函数

  • 直到遇到fullName(),准备调用函数,建立函数 fullName 的执行环境,将其压入栈顶并开始执行函数

    fullName入栈
  • 函数 fullName 执行时没有再生成执行环境,执行完毕后则从栈顶弹出

    fullName出栈
  • fullName 执行栈弹出后,控制权回到了 getName 的执行栈,继续执行代码,执行完毕,从栈顶弹出

  • 最后回到了全局环境,窗口关闭后弹出 执行栈示意图

结论

  • 单线程,同步执行,只有栈顶的环境处于执行中,其他环境须要等待。
  • 执行 JS 程序,首先进入全局环境,全局环境只有一个并在关闭窗口时弹出。
  • 函数调用时会建立新的执行环境,包括调用本身。
相关文章
相关标签/搜索