手机版

深入理解JavaScript中的执行上下文和执行栈

时间:2021-08-29 来源:互联网 编辑:宝哥软件园 浏览:

如果你是或者想成为一名JavaScript开发人员,你必须知道JavaScript程序是如何在内部执行的。理解执行上下文和执行栈对于理解其他JavaScript概念非常重要,例如变量声明提升、范围和闭包。

正确理解执行上下文和执行栈的概念将使您成为更好的JavaScript开发人员。

简而言之,让我们开始:)

从Bit共享的博客

使用Bit应用程序提供的组件作为构建块,你就是一个架构师。随时随地与您的团队共享、发现和开发组件。来试试吧!

位共享和创建代码组件:位可以帮助您在不同的项目和应用程序中共享、发现和使用代码组件,以创建新的函数和…

什么是执行上下文?

简而言之,执行上下文是评估和执行JavaScript代码的环境的抽象概念。每当Javascript代码运行时,它都会在执行上下文中运行。

执行上下文的类型

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

全局执行上下文—这是默认的或基本的上下文,任何不在函数内部的代码都在全局上下文中。它做两件事:创建一个全局窗口对象(在浏览器的情况下),并将这个的值设置为等于这个全局对象。程序中只有一个全局执行上下文。函数执行上下文—每当调用函数时,都会为该函数创建一个新的上下文。每个函数都有自己的执行上下文,但它是在调用函数时创建的。可以有任意数量的函数上下文。每当创建新的执行上下文时,它将按照定义的顺序执行一系列步骤(这将在后面讨论)。Eval函数执行上下文—在eval函数内部执行的代码也将有自己的执行上下文,但是由于JavaScript开发人员不经常使用eval,所以我在这里不讨论它。执行栈

执行栈,在其他编程语言中也称为“调用栈”,是一个具有LIFO数据结构的栈,用于存储代码运行时创建的所有执行上下文。

当JavaScript引擎第一次遇到您的脚本时,它将创建一个全局执行上下文,并将其推入当前执行堆栈。每当引擎遇到函数调用时,它都会为函数创建一个新的执行上下文,并将其推到堆栈的顶部。

引擎执行其执行上下文位于堆栈顶部的函数。当此函数的执行结束时,执行上下文从堆栈中弹出,控制流到达当前堆栈中的下一个上下文。

让我们通过下面的代码示例来理解这一点:

让a='你好世界!';函数优先(){ console . log(' Inside first function ');second();console.log('再次在第一个函数内部');}函数second(){ console . log(' Inside second function ');} first();console.log('内部全局执行上下文');上述代码的执行上下文堆栈。

当上述代码加载到浏览器中时,JavaScript引擎会创建一个全局执行上下文,并将其推入当前执行堆栈。调用第一个()函数时,JavaScript引擎会为该函数创建一个新的执行上下文,并将其推送到当前执行堆栈的顶部。

当从第一个()函数内部调用第二个()函数时,JavaScript引擎会为第二个()函数创建一个新的执行上下文,并将其推到当前执行堆栈的顶部。当第二个()函数完成执行时,其执行上下文从当前堆栈中弹出,控制流到达下一个执行上下文,即第一个()函数的执行上下文。

执行first()时,其执行上下文从栈中弹出,控制流到达全局执行上下文。一旦执行完所有代码,JavaScript引擎就会从当前堆栈中移除全局执行上下文。

如何创建执行上下文?

到目前为止,我们已经看到了JavaScript如何管理执行上下文。现在让我们了解一下JavaScript引擎是如何创建执行上下文的。创建执行上下文有两个阶段:1)创建阶段和2)执行阶段。

创作阶段

在执行JavaScript代码之前,执行上下文将经历创建阶段。在创建阶段会发生三件事:

该值的确定称为此绑定。创建词法环境组件。创建可变环境组件。因此,执行上下文在概念上表示如下:

execution context={ this binding=this value,词典环境=}.},variableenvironment={.},}此绑定:

在全局执行上下文中,这个的值指向一个全局对象。(在浏览器中,这是指窗口对象。).

在函数执行的上下文中,其值取决于如何调用函数。如果它被引用对象调用,它将被设置为该对象,否则它的值将被设置为全局对象或未定义(在严格模式下)。例如:

让foo={ baz : function(){ console . log(this);} } foo . baz();//“this”指的是“foo”,因为“baz”是由//object“foo”let bar=foo . baz调用的;bar();//“this”指向全局窗口对象,因为//未指定引用对象的词法环境

ES6官方文档将词汇环境定义为

词法环境是一种规范类型,它基于ECMAScript代码的词法嵌套结构来定义标识符与具体变量和函数之间的关联。词汇环境由一个环境记录器和一个可能的空值组成,空值指的是外部词汇环境。

简单地说,词法环境是一个保存标识符-变量映射的结构。(这里的标识符是指变量/函数的名称,变量是对实际对象[包括函数类型对象]或原始数据的引用)。现在,词汇环境有两个组成部分:(1)环境记录器和(2)对外部环境的引用。

环境记录器是存储变量和函数声明的实际位置。对外部环境的引用意味着它可以访问其父词法环境(范围)。词汇环境有两种类型:

全局环境(在全局执行上下文中)是一个没有外部环境引用的词法环境。全局环境的外部环境引用为空。它有内置的对象/数组等。环境记录器中的原型函数(与全局对象相关联,如window对象)和任何用户定义的全局变量,并且这个的值指向全局对象。在函数环境中,函数内部的用户定义变量存储在环境记录器中。被引用的外部环境可以是全局环境,也可以是包含该内部函数的任何外部函数。环境记录仪也有两种类型(如上!):

声明性环境记录器存储变量、函数和参数。对象环境记录器用于定义全局上下文中出现的变量和函数之间的关系。简而言之,

在全局环境中,环境记录器是对象环境记录器。在功能环境中,环境记录器是一个声明性环境记录器。

注意—对于函数环境,声明性环境记录器还包含传递给函数的参数对象(存储索引和参数的映射)以及传递给函数的参数长度。

从抽象的角度来看,伪代码中的词法环境是这样的:

GlobalExectionContext={词典环境: { environmentrecord : { type : ' Object ',//在此绑定标识符} outer : null }} functionexecutioncontext={词典环境3360 { environmentrecord : { type : ' declarative ',//在此绑定标识符} outer :全局或外部函数环境引用} }环境变量:

它也是一个词法环境,它的环境记录器保存执行上下文中变量声明语句创建的绑定关系。

如上所述,变量环境也是一个词法环境,因此它具有上面定义的词法环境的所有属性。

在ES6中,词法环境组件和变量环境的区别在于,前者用于存储函数声明和变量(let和const)绑定,而后者仅用于存储var变量绑定。

让我们看一下示例代码来理解上面的概念:

设a=20const b=30风险值c;函数乘法(e,f){ var g=20;返回e * f * g;}c=乘法(20,30);执行上下文如下所示:

Global executioncontext={ this bind : Global Object,词典式环境: { environment record : { type : ' Object ',//此处绑定标识符a:未初始化,b:未初始化,乘3360 func}外部: null},变量environment : { environment record 3: { type 3: ' Object ',//此处绑定标识符c:未定义。} outer : null } } FunctionExectionContext={ thisbind : Global Object,词法环境3360 { Environment Record : { Type 3: ' Declarative ',//这里绑定标识符参数3360 { 03: 20,13: 30,长度3: 2 },},outer 3: globaliexcalenvironment },变量环境3: { Environment Record 3: { Type 33:

也许你已经注意到,由let和const定义的变量与任何值都没有关联,但是由var定义的变量被设置为undefined。

这是因为在创建阶段,引擎检查代码以找出变量和函数声明。虽然函数声明完全存储在环境中,但是变量最初被设置为未定义(在var的情况下)或未初始化(在let和const的情况下)。

这就是为什么您可以在声明之前访问var定义的变量(尽管未定义),但是在声明之前访问let和const的变量将会得到一个引用错误。

这就是我们所说的变量声明提升。

执行阶段

这是整篇文章最简单的部分。在这个阶段,所有这些变量都被赋值,最后代码被执行。

注意—在执行阶段,如果JavaScript引擎在源代码中声明的实际位置找不到let变量的值,它将被分配为未定义。

结论

我们已经讨论了JavaScript程序如何在内部执行。虽然要成为一名优秀的JavaScript开发人员并不需要学习所有这些概念,但是对上述概念的良好理解将有助于您更容易、更深入地理解其他概念,例如变量声明提升、作用域和闭包。

就这样。如果你觉得这篇文章有用,请点击按钮,在下面自由评论!我很乐意和你讨论这件事。

从Bit共享的博客

Bit使得在项目和应用程序中共享小组件和模块变得非常简单,这样您和您的团队就可以更快地构建代码。随时随地与您的团队共享、发现和开发组件,并尽早尝试!

位共享和创建代码组件:位可以帮助您在不同的项目和应用程序中共享、发现和使用代码组件,以创建新的函数和…

摘要

以上是边肖介绍的JavaScript中的执行上下文和执行栈,希望对大家有所帮助。如果你有任何问题,请给我留言,边肖会及时回复你。非常感谢您对我们网站的支持!

版权声明:深入理解JavaScript中的执行上下文和执行栈是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。