理解JavaScript的执行上下文和执行上下文栈

204 阅读2分钟

执行上下文(EC)是什么?

简而言之,执行上下文就是当前JavaScript代码被解析和执行时所在环境的抽象概念, JavaScript 中运行任何的代码都是在执行上下文中运行

执行上下文的类型

  • 全局执行上下文: 这是默认的、最基础的执行上下文。不在任何函数中的代码都位于全局执行上下文中。它做了两件事:1.创建一个全局对象,在浏览器中这个全局对象就是 window 对象。2.将this指针指向这个全局对象。一个程序中只能存在一个全局执行上下文。
  • 函数执行上下文: 每次调用函数时,都会为该函数创建一个新的执行上下文。每个函数都拥有自己的执行上下文,但是只有在函数被调用的时候才会被创建。一个程序中可以存在任意数量的函数执行上下文。每当一个新的执行上下文被创建,它都会按照特定的顺序执行一系列步骤,具体过程将在本文后面讨论。
  • Eval 函数执行上下文:运行在eval函数中的代码也获得了自己的执行上下文。

执行上下文栈(ECStack)

已知函数调用前会创建执行上下文,那么JS引擎是怎么管理这么多执行上下文的?

可以利用数组模拟一下ECStack。

ECStack = []

整个JS代码开始运行前,会创建 GlobalContext

ECstack.push(GlobalContext)

以下代码执行时

function a(){
    b()
}

function b() {
    c()
}

function c() {
    d()
}
function d(){
    console.log('d')
}

a()

当引擎发现a被调用时

ECstack.push(func<a>Context)

a的执行上下文入栈后,开始执行函数体,此时发现b被调用

ECstack.push(func<b>Context)

此时执行b的函数体,同理

ECstack.push(func<c>Context)
ECstack.push(func<d>Context)

当d的执行上下文入栈后,执行console.log('d')后发现函数执行结束

ECstack.pop()// 栈结构    最后入栈的元素最先出栈
// 同理 发现c函数也执行完毕
ECstack.pop()
ECstack.pop()
ECstack.pop()

直到全部出栈只剩下GlobalContext.

执行上下文的作用

引擎创建和管理执行上下文的目的是为了什么呢?

简单将执行上下文抽象为一个执行环境对象。

它包含三个重要属性:

  • 变量对象
  • 作用域链
  • this