Skip to content

【JS基础】执行上下文和执行栈

在JavaScript的世界里,了解执行上下文(Execution Context)和执行栈(Call Stack)是理解语言工作原理的关键。这些概念是JavaScript代码执行的基石,帮助我们理解函数是如何被调用的,变量是如何被存储的,以及代码是如何按顺序执行的。本文将通过示例详细介绍这些概念,帮助你深入理解JavaScript的工作机制。

执行上下文(Execution Context)

执行上下文是JavaScript代码被评估和执行时的环境。每当JavaScript代码运行时,它都是在一个执行上下文中运行的。可以简单地将执行上下文视为一个对象,它包含了代码执行时的所有必要信息。

JavaScript有三种类型的执行上下文:

  • 全局执行上下文

这是默认或基础的上下文,任何不在函数内部的代码都在全局上下文中。它负责创建全局对象(在浏览器中是window对象)和设置this的初始值为这个全局对象。一个程序中只会有一个全局执行上下文。

  • 函数执行上下文

每当一个函数被调用时,都会为该函数创建一个新的上下文。函数上下文可以访问其父上下文中的变量,这就是闭包的原理。

  • Eval执行上下文

执行在eval函数内部的代码也会有它自己的执行上下文,但由于eval的使用不被推荐,这里不做过多讨论。

每个执行上下文都有三个重要的属性:

  • 变量对象(Variable Object,VO)

包含了上下文中定义的所有变量和函数声明。

  • 作用域链(Scope Chain)

用于解析变量的作用域。

  • this指针

指向上下文相关的对象。

执行栈(Call Stack)

执行栈,也称为"调用栈",用于存储在代码执行期间创建的所有执行上下文。JavaScript是一种单线程语言,意味着它一次只能执行一个任务。执行栈就是遵循后进先出原则来管理执行上下文的结构。

当脚本开始执行时,JS引擎首先会创建一个全局执行上下文并将其推入执行栈。每当一个函数被调用,JS引擎就会为该函数创建一个新的执行上下文并将其推入栈顶。当当前函数执行完毕后,其对应的执行上下文会从栈顶被弹出,控制权回到当前栈顶的上下文。

示例

javascript
function third() {
    console.log('执行 third 函数');
}

function second() {
    third();
    console.log('执行 second 函数');
}

function first() {
    second();
    console.log('执行 first 函数');
}

first();
console.log('全局执行上下文');
function third() {
    console.log('执行 third 函数');
}

function second() {
    third();
    console.log('执行 second 函数');
}

function first() {
    second();
    console.log('执行 first 函数');
}

first();
console.log('全局执行上下文');

执行流程如下:

  1. 创建全局执行上下文,推入执行栈。
  2. 遇到first()调用,为first函数创建执行上下文并推入执行栈。
  3. 在first函数内部,调用second(),为second函数创建执行上下文并推入执行栈。
  4. 同理,second函数中调用third(),为third函数创建执行上下文并推入执行栈。
  5. third函数执行完毕,打印"执行 third 函数",其执行上下文从执行栈中弹出。
  6. 控制权回到second函数,继续执行打印"执行 second 函数",second的执行上下文从栈中弹出。
  7. 然后是first函数,打印"执行 first 函数",first的执行上下文弹出。
  8. 最后回到全局执行上下文,打印"全局执行上下文",脚本结束。

通过这个例子,我们可以看到函数调用如何形成一个由执行栈管理的执行上下文的层次结构。理解这个过程对于深入学习JavaScript至关重要。

上次更新于: