【译】JavaScript 执行上下文2 — 调用栈和多个执行上下文

134 阅读4分钟

在上一篇文章中,我们讨论了执行上下文。这是在编译步骤中创建的第一个执行上下文。

我们将其称为第一个执行上下文,全局执行上下文 global execution context ( global EC )。对应变量环境中存储的变量就是全局变量 global variables。

image.png

全局执行上下文不同步。运行脚本时可以创建和删除多个执行上下文。

这些执行上下文从哪里来?

执行上下文始终链接到编译步骤。多个执行上下文意味着许多编译步骤。

该机制与 function 相关。

image.png

让我们看一个带有函数的示例。

我们知道控制台在执行结束时打印“20”,但是执行上下文中发生了什么?

与往常一样,它从编译步骤开始,并创建一个全局执行上下文。

image.png

在变量环境中,我们看到“apple”和“appleTotal”变量以及“total”函数。编译结束,开始执行。

image.png

“apple”变量更新为“10”,然后 JavaScript 引擎读取“total()”部分。

此时,重复相同的两步过程。编译步骤再次开始,但这一次,仅发生在“total”函数中。

image.png

JavaScript 引擎创建一个新的执行上下文,即“total”执行上下文,并将其堆叠在全局执行上下文之上。

我们称这种结构为栈。

栈有一个独特的特点:后进先出。这是我们在此机制中唯一关心的功能。

image.png

与全局环境相同,“total”执行上下文中存在一个变量环境,其中有一个未定义的“price”变量。

image.png

接下来,在“total”执行上下文中,执行步骤开始。 “price”变量更新为“2”。

然后,该函数在“total”执行上下文中查找“price”变量,并在全局执行上下文中查找“apple”变量。

很好,它找到了两个变量,并返回了计算结果。

同时,返回值被分配给全局执行上下文中的“appleTotal”变量。

image.png

“total”执行上下文中没有剩余的可执行脚本,因此 JavaScript 引擎将其从栈中删除。

“total”执行上下文是最后一个进入栈的执行上下文,因此它是第一个离开栈的执行上下文。

image.png

现在我们有了栈底部的最后一个,即全局执行上下文。

唯一剩下的可执行脚本是在控制台中打印变量“appleTotal”。这样做之后,整个过程就完成了。

从这个例子中,我们可以看到JavaScript引擎是如何管理执行上下文的。

  • 在调用函数之前,JavaScript 引擎不会编译函数中的代码。
  • 编译函数时,会创建一个新的执行上下文并将其放在堆栈顶部。
  • 所有执行上下文都在堆栈结构中进行管理。该过程从堆栈顶部到底部发生。
  • 每当调用函数时,就会发生编译和执行这两个步骤的过程。

根据执行上下文堆叠在彼此顶部的方式,我们将其称为调用栈。

在浏览器中检查 JavaScript 调用栈

现代浏览器可以轻松地在其开发工具中检查调用堆栈。这是 Chrome 的示例。

要检查调用堆栈,我们需要

  1. HTML 文件,以及
  2. 一个断点

以下代码适用于 HTML 文件,但您始终可以编写自己的代码。

<script>
  var apple = 10;function total() {
    var price = 2;
    return apple * price;
  }var appleTotal = total();console.log(appleTotal);
</script>

image.png

在 Chrome 中运行 HTML 文件,然后打开开发工具中的“Sources”面板。

image.png 在“Sources”面板上,我们在“total”函数中添加一个断点。

接下来,刷新页面,调用栈显示。 “total”是“total”执行上下文,“anonymous”是全局执行上下文。

要点

  • 多个执行上下文以栈结构进行管理。它是 JavaScript 调用栈。
  • JavaScript 引擎重复编译和执行两步过程,以添加和删除执行上下文。
  • 新的执行上下文会添加到最上面,最上面的执行上下文优先先完成。
  • 只有一个全局执行上下文,并且它始终位于调用栈的底部。它在浏览器开发工具中显示为“匿名”。

参考

  • 值得一提的是,调用堆栈并不是后端编程世界中定义的真正的堆栈数据结构。浏览器模拟的是栈数据结构,所以它们并不完全相同。
  • 如果您对堆栈数据结构感到好奇,这个回复分享了一个有趣的类比。
  • 如果您使用的是 Firefox,这篇文章可以帮助您检查调用堆栈。
  • freeCodeCamp 团队在调用堆栈上发表了一篇很棒的文章,其中包含更多代码示例。