JavaScript 调用栈

17 Mar 2025 | 4 分钟阅读

为了管理执行上下文,JavaScript 引擎使用调用栈。JS 调用栈的工作是内部进行的,但我们将在此处理解其工作原理。

在本节中,我们将讨论 JavaScript 调用栈及其工作原理。我们还将讨论一个示例,该示例将使我们更好地理解这个概念。

什么是 JS 调用栈

JavaScript 执行上下文(全局执行上下文和函数执行上下文)由 JavaScript 引擎执行。为了管理这些执行上下文,JS 引擎使用调用栈。因此,JS 调用栈是一种数据结构,用于跟踪正在调用和执行的函数的信息。因此,如果用户调用一个函数进行执行,该指定的函数将被推入/添加到调用栈中,当用户从函数返回时,意味着该函数已从调用栈中弹出。因此,调用栈是一个普通的栈数据结构,遵循栈的 LIFO(后进先出)原则。

JavaScript 调用栈的作用

JS 引擎在以下几点使用调用栈:

  • 当用户执行任何脚本时,JS 引擎会创建一个全局执行上下文,然后将其添加到调用栈的顶部,以便对其进行执行。
    JavaScript Call Stack
  • 当调用任何函数时,JS 引擎会创建一个函数执行上下文,并将其添加到栈顶,以便被调用的函数可以执行。
    JavaScript Call Stack
  • 如果一个函数调用了另一个函数,JS 引擎会为被调用的函数创建一个函数执行上下文,将其添加到栈顶,并开始执行。
    JavaScript Call Stack
  • 当任何函数的执行完成时,JS 引擎会将其从栈中弹出,并继续执行栈中存储的其他函数。
    JavaScript Call Stack
  • 如果栈中没有剩余空间并且我们尝试推送更多函数,则会抛出“堆栈溢出”错误;如果调用栈中没有进一步的执行上下文,则会抛出“堆栈下溢”错误。

JavaScript 调用栈示例

让我们看一个示例来理解 JavaScript 调用栈函数的使用。

代码如何工作

在上面的代码中,我们创建了两个函数 getSum() 和 findavg(),脚本的执行将按照以下步骤开始:

  1. 当脚本开始执行时,JS 引擎最初会创建一个全局执行上下文(即 global() 函数),并将其添加到调用栈的顶部。
  2. 全局执行在进入创建阶段后,会进入生命周期的执行阶段,如下图所示。
    JavaScript Call Stack
  3. 调用 findavg(10, 20) 函数,JS 引擎为其创建函数执行上下文。然后将其推送到调用栈的顶部。
  4. 因此,现在调用栈中推送了两个函数,即 global() 和 findavg(),findavg() 函数位于栈的顶部,如下图所示。
    JavaScript Call Stack
  5. JS 引擎开始执行 findavg() 函数,因为它位于栈顶,如下图所示。
    JavaScript Call Stack
  6. 由于在代码中,getSum() 函数在 findavg() 函数定义内部被调用,因此 JS 引擎为 getSum() 函数创建函数执行上下文,并将其推送到栈顶。
  7. 现在,栈中有三个函数,即 global()、findavg() 和 getSum() 函数,如下图所示。
    JavaScript Call Stack
    如您下文所示,有两个函数执行上下文和一个全局执行上下文。
    JavaScript Call Stack
  8. 因此,JS 引擎首先执行 getSum() 函数并将其从调用栈中弹出。
    JavaScript Call Stack
  9. 同样,findavg() 函数执行完毕并从调用栈中退出。
    JavaScript Call Stack
  10. 由于两个函数的执行都已完成,并且调用栈中没有其他函数可供执行。JS 引擎停止调用栈的执行,并继续执行其他执行任务。

调用栈何时溢出

JavaScript Call Stack

当调用栈中没有更多空间时,就会发生溢出情况,或者当存在没有退出点的递归函数时,也可能发生这种情况。JavaScript 调用栈具有固定的大小,该大小取决于宿主环境(即 Node.js 或 Web 浏览器)的实现。因此,当超出栈的定义大小时,就会发生堆栈溢出。因此,它会抛出堆栈溢出错误。

示例

以下示例描述了堆栈溢出情况。

因此,在上面的代码中,我们可以看到我们递归调用了 **test()** 函数,这意味着该函数将执行,直到宿主环境的最大调用大小超过,因此栈会抛出堆栈溢出错误。

需要注意的点

JavaScript 是一种同步和单线程编程语言。这意味着当任何脚本执行时,JS 引擎会从上到下逐行执行代码。因此,JavaScript 引擎只有一个调用栈,一次只能做一件事情。