订阅我的时事通讯,随时了解我的最新博客帖子。每次我发布新东西时都会收到一封电子邮件。
执行上下文是JavaScript编程语言最基本的部分。在这篇文章中,我们将深入探讨这一概念,它不仅是基本的,而且非常容易理解。
在许多情况下,从学习的理解和复杂性的角度来看,执行上下文的概念被投射为高级JavaScript概念。是的,如果没有按照正确的顺序用适当的例子学习,这听起来可能很复杂。随之而来的是,每个JavaScript初学者都需要理解,为什么对这个基本概念充满信心是很重要的呢?
这是名为“JavaScript:破解坚果”系列文章的第二篇。如果您还没有阅读关于JavaScript解释或编译的第一篇文章,请尝试一下。希望你喜欢这本书。
如果你还没有读过这个系列的前一篇文章,你可以在这里找到它:JavaScript解释的还是编译的?辩论结束了。
一些研究表明,人脑记忆中的信息量可能和整个互联网上的信息量一样多!但是我们不应该认为这是理所当然的,对吗?因此,一个合理的问题可能是,为什么学习这个概念很重要?
JavaScript的执行上下文是正确理解许多其他基本概念的基础。我们经常在下面的每一个概念中发现很多误解,仅仅是因为我们误解了执行上下文背后的事实。
作为JavaScript开发人员,一旦我们对这些概念有了很好的理解,我们就能够
我不知道为什么,但大多数编程语言都充满了有时可能会令人气馁的繁重术语。这些繁重的单词背后的基本概念大多更简单,更容易掌握。以下是对这篇文章有用的几点:
解析器:解析器或语法解析器是一个逐行读取代码并了解它如何符合编程语言定义的语法以及它要做什么的程序。正如您在我的上一篇文章中看到的,JavaScript语法解析器获取令牌数组并创建抽象语法树(AST),以便可以对其进行进一步处理以创建可执行代码。
词汇环境:单词词汇的意思,与一种语言的单词或词汇有关。词法环境意味着代码的物理编写方式和位置。让我们以这段代码为例,
在上面的代码中,变量名在函数sayName中。这一点很重要,请注意,您的程序不能像在计算机上那样运行。它必须由编译器翻译。因此,它必须正确地知道和映射什么在词法上所处的位置,以便编译后的输出也是有意义和有效的。
请注意,通常在您的代码中会有很多词法环境。但不会同时执行所有环境。我们很快就会看到这一点。
上下文:将单词上下文可视化的最好方法是,想像一个围绕您感兴趣的主题(或我们正在讨论的上下文)的圆圈(或包装器)。上下文是围绕特定事件、情况等的一组情况或事实。
执行上下文:这意味着当前正在运行的代码及其周围的一切都在帮助运行它。可以有很多可用的词法环境,但是当前运行的是由执行上下文管理的。
作为软件开发人员,我们喜欢(或希望)以这样一种方式编写代码,它看起来不那么复杂,易于维护,并遵循一些实践、标准等。通过相同的类比,执行上下文允许JavaScript引擎以更好的方式维护代码和管理复杂性。
无论何时在JavaScript中运行代码,它都会在执行上下文中运行,执行上下文是代码加上我们在这里看到的由JavaScript引擎完成的所有操作(标记化、解析、代码生成等)的组合。
每当JavaScript代码第一次运行时,它都会创建称为全局执行上下文(Global Execution Context,GEC)的东西。即使在.js文件中没有一行代码并加载它,也会创建全局执行上下文。
全球这个词在这里是什么意思?函数之外的任何东西都是全局的。
全局执行上下文也称为基本执行上下文。它为你创造了两个特别的东西,
称为浏览器的窗口对象的全局对象。如果您在服务器端使用JavaScript,比如NodeJS,那么它将不是Window。
为简单起见,获取一个名为index.js的空JavaScript文件,并将其导入到一个名为index.html的html文件中,如下所示:
一旦您将此html加载到浏览器上,将不会加载和执行任何JavaScript,但是,如果您打开调试器控制台(Chrome为F12)并键入以下内容,
您看,已经为您创建了一个名为“这”的东西。您也可以尝试键入Window,这一次您将打印Window对象,
您是否注意到,Window对象和this变量在全局执行上下文中都是相等的?试试这个来确认一下,
当全局执行上下文刚刚在没有任何JavaScript代码的情况下被创建时,可以将其可视化为,
现在让我们向js文件添加一些代码。我们添加了一个名为name的变量,并用值Tom进行了初始化。我们还有一个名为sayName()的函数,它只记录名称。
您认为现在全球执行环境将会发生什么情况?让我们先在下面的图片演示中看到它,然后再进行解释。
在全局执行上下文中创建有两个阶段,即创建阶段和执行阶段。
创建阶段:在这个阶段,创建了两个特殊的东西,即全局对象,如浏览器的Window和一个名为this的变量。
变量名由一个名为UNDEFINED的特殊值初始化。函数sayName()直接放入内存中,我们将在下一篇关于另一个概念(提升)的文章中看到更多关于它的信息。
执行阶段:在此阶段,代码实际开始执行。对于上面的示例,唯一要发生的事情是,它会将值Tom赋给变量名。请注意,我们没有调用函数sayName(),尽管我们已经定义了它。因此,此函数将不会执行。我们将在下一节中了解有关函数执行的内容。
让我们看看下面的例子来理解这个概念。在本例中,我们有一个名为name的全局变量,它被分配了一个名为Tom的值。我们有一个名为tom()的函数来记录名称。最后,我们调用函数tom()。
请参阅下面的演示,一起理解函数执行上下文和全局执行上下文。
正如我们在上面看到的,全局执行上下文的创建阶段创建全局对象,此变量为变量和函数创建内存。该变量使用名为unfined的特殊值进行初始化。
在执行阶段,它为变量赋值并调用函数。因此创建了函数执行上下文。
函数执行上下文经历相同的阶段,即创建和执行。需要注意的重要一点是,函数执行上下文可以访问一个名为Arguments的特殊变量,它是调用时传递给函数的参数。在我们的示例中,我们不传递任何参数。因此,长度为0。
一个函数可以调用另一个函数,也可以调用另一个函数,以此类推。对于每个函数调用,都将创建一个函数执行上下文。我们将在即将发布的关于范围的帖子中详细介绍这一概念。
默认情况下,它指向窗口对象(还有更多内容,我们将在以后的帖子中看到)。
将任何函数声明放入内存时,为变量声明指定默认值UNDEFINED
将任何函数声明放入内存时,为变量声明指定默认值UNDEFINED。此外,函数执行上下文创建它们自己的执行堆栈。
全局和函数执行上下文以及阶段(创建和执行)是需要熟悉的重要概念。这将有助于轻松理解作用域、异步函数、闭合、提升等。我们将在本系列即将发布的文章中详细介绍每个概念。
如果您不熟悉执行上下文的概念,请在学习此概念时并排使用JavaScript Visualizer工具。编写小函数,使用定义的变量,执行函数,并查看该工具如何将其带过执行上下文的各个阶段。
如果它对你有用,请点赞/分享,这样其他人也能收到。要获得有关我最新帖子的电子邮件通知,请点击页面顶部的订阅按钮订阅我的博客。
在本系列的下一篇文章中,我将解释另一个基本概念,即吊装。敬请关注。