JavaScript 执行上下文2025年3月17日 | 阅读13分钟 对于 JavaScript 开发者或想要深入了解 JavaScript 工作原理的人来说,这个主题非常重要。 在本节中,我们将学习和理解 JavaScript 的执行上下文,包括它是什么、类型、执行栈,执行上下文是如何创建的以及关于执行阶段的所有内容。我们将逐点讨论。让我们先从介绍部分开始。 什么是执行上下文?执行上下文是描述代码内部工作原理的概念。在 JavaScript 中,使 JavaScript 代码能够执行的环境称为 JavaScript 执行上下文。正是执行上下文决定了代码的哪个部分可以访问代码中使用的函数、变量和对象。在执行上下文中,特定的代码会被逐行解析,然后变量和函数会被存储在内存中。执行上下文类似于一个容器,用于存储变量,然后代码会被求值并执行。因此,执行上下文为特定代码的执行提供了环境。 执行上下文的类型JavaScript 中执行上下文的类型有:
开始逐一讨论 全局执行上下文GEC / 全局执行上下文也称为基础/默认执行。任何不位于任何函数中的 JavaScript 代码都将存在于全局执行上下文中。其名称“默认执行上下文”的原因在于,当文件首次在 Web 浏览器中加载时,代码就开始执行。GEC 执行以下两项任务:
根据以上介绍,应该理解的是,每个代码中只有一个全局执行上下文,因为 JS 引擎是单线程的,因此,只有一个全局环境可以用于执行 JavaScript 代码。 函数执行上下文FEC 或函数执行代码是 JavaScript 引擎在找到任何函数调用时创建的一种上下文。每个函数都有自己的执行上下文,因此与 GEC 不同,FEC 可以不止一个。此外,FEC 可以访问 GEC 的全部代码,但 GEC 无法访问 FEC 的全部代码。在 GEC 代码执行期间,会启动一个函数调用,当 JS 引擎找到它时,会为该特定函数创建一个新的 FEC。 Eval 函数执行上下文在 eval 函数中执行的任何 JS 代码都会创建并保留自己的执行上下文。但是,eval 函数不被 JavaScript 开发者使用,但它是执行上下文的一部分。 执行栈执行栈也称为 调用栈。 栈是一种数据结构,它以 LIFO(后进先出)的形式存储值。同样,执行栈是一个跟踪脚本生命周期中创建的所有执行上下文的栈。JavaScript 开发者必须知道 JavaScript 是单线程工作的,它一次只能在 Web 浏览器中执行一项任务。因此,对于其他操作、函数和事件,会创建一个栈,称为 执行栈。执行栈的底部是 GEC,它是默认存在的。因此,当开始 JS 代码执行时(即,在 GEC 执行期间),如果代码中存在任何函数,并且 JS 引擎搜索它,它会立即为该函数创建一个函数执行上下文 (FEC) 并将其推送到执行上下文栈的顶部。位于执行上下文栈顶部的特定执行上下文将始终由 JS 引擎首先执行。一旦所有代码的执行完成,JS 引擎就会弹出函数的执行上下文,然后继续下一个,依此类推。通常,当脚本在浏览器中加载时,第一个元素将是全局执行上下文。但是,当检测到函数执行时,就会创建执行上下文并将其虚拟放置在 GEC 的顶部。此过程将一直持续到整个代码执行完成。 为了理解执行栈的工作原理,让我们看下面的示例代码 这是一个用于理解其工作原理的示例代码。 说明
执行栈的执行就这样进行。 创建执行上下文首先创建一个执行上下文,然后对其进行管理。执行上下文的创建有两种方式: 创建阶段创建阶段是指 JS 引擎调用函数但尚未开始执行的阶段。在此阶段,JS 引擎开始其编译阶段,扫描特定函数的代码进行编译,但不执行代码。执行上下文的创建由 JavaScript 引擎负责,它通过执行以下描述的任务来创建: 任务 1:创建激活对象/变量对象: JavaScript 的一个特殊对象,类似于一个容器,其中包含函数参数、变量以及内部函数声明的所有信息。它没有 dunder proto 属性。 任务 2:创建作用域链: 完成任务 1 后,JS 引擎初始化作用域链。作用域链是一个列表,包含当前函数存在的范围内的所有变量对象。作用域链还包含 GEC 的变量对象,并携带当前函数的变量对象。
让我们通过下面的例子来理解激活对象的创建 示例代码 1 现在,在调用 test() 之后,执行其代码之前,JS 引擎为示例代码 1 创建了一个 executionContextObj。如下面的代码所示: 激活对象包含参数对象,该对象进一步包含关于函数参数的详细信息。它具有当前函数中声明的每个函数和变量的属性名称。在我们的例子中,示例代码 1 的激活对象将是: 说明
因此,创建阶段就是这样工作的。 执行阶段执行阶段是创建阶段完成后的下一个阶段。执行阶段是 JS 引擎再次扫描代码中的函数,即再次更新变量对象中的变量值并运行代码的阶段。让我们看看我们上面讨论的示例的执行阶段或完整代码: 示例代码 2 首先,上面的代码在浏览器中加载。之后,JS 引擎开始其编译阶段以创建执行对象。在编译阶段,JS 引擎仅处理声明,而不关心值。 现在,在执行阶段,将按照每行描述的顺序执行以下步骤:
因此,创建阶段和执行阶段的工作就是这样进行的。 创建阶段后的 GEC 对象 在上面的解释中,我们看到了如何为示例代码 2 通过执行和创建阶段创建执行栈。然而,我们应该更深入地理解上述代码的 GEC 和 FEC 的工作原理。考虑示例代码 2 的以下 GEC 对象代码: 如您在上面看到的,没有剩余代码了,JS 引擎会进入执行阶段,再次扫描函数。JS 引擎会按照下面每行描述的方式更新变量值然后执行代码:
现在,让我们看看执行阶段后的 GEC 对象。 执行阶段后的 GEC 对象 在我们的示例代码 2 中:
编译阶段后的 z 执行对象 下面是编译阶段完成后 FEC 对象的代码: 示例代码 2 的编译阶段后的代码如下所示:
执行阶段后的 z 的执行上下文对象 在示例代码 2 中:
因此,执行上下文就是这样创建和定义的。 全局执行上下文与函数执行上下文两者之间存在以下区别:
|
我们请求您订阅我们的新闻通讯以获取最新更新。