了解JavaScript执行上下文
执行上下文 是 JavaScript 编程语言最基本的部分。在这篇文章中,我们将深入探讨这个概念以找出答案,它不仅是基本的,而且易于理解。
在许多情况下,从学习的理解和复杂性的角度来看,执行上下文 的概念被预测为 高级JavaScript概念。是的,如果没有按照正确的顺序学习适当的示例,这听起来可能很复杂。每个 JavaScript 初学者都需要理解为什么对这个基本概念充满信心很重要。
为什么这个概念很重要?
一些研究表明,人类大脑在其记忆中所能容纳的信息可能与整个互联网所包含的信息一样多!但是我们不应该认为这是理所当然的,对吗?因此,一个有效的问题可能是,为什么这个概念对学习很重要?
JavaScript 的执行上下文是正确理解许多其他基本概念的基础。我们经常发现以下每个概念都有很多误解,只是因为我们误解了 执行上下文 背后的事实。
- 提升
- 作用域
- 作用域链
- 闭包
- 事件循环
作为一名 JavaScript 开发人员,一旦我们对这些概念有了很好的理解,我们就能够
- 🐛 在源代码中引入较小的错误
- 👩🏫 成为做伟大代码审查的老板
- 👀 调试的好眼睛。
- 🏭 解决生产问题的更简单方法
不要被压倒
一句鼓励的话,如果你是新手,不要不知所措。
大多数编程语言都充满了沉重的术语,这可能会令人沮丧。这些沉重词汇背后的基本概念大多简单易懂。以下是对这篇文章有用的一些:
- 解析器-Parser:解析器或语法解析器是一个程序,用于逐行读取您的代码,并了解它如何符合编程语言定义的语法以及它应该做什么。JavaScript语法解析器获取标记数组并创建抽象语法树(AST),以便进一步处理以创建执行代码。
- 词法环境-Lexical Environment:词法这个词的意思是与某事相关。词法环境意味着您的代码在物理上的放置方式和位置。让我们以这段代码为例,
function sayName() {
var name = 'someName';
console.log('The name is, ', name);
}
在上面的代码中,变量name在词法上位于函数sayName中。现在,需要注意的是,您的程序不会按原样在计算机上运行。它必须由编译器翻译。因此,编译器必须知道并正确映射词法上的位置。它也需要有意义和有效。请注意;通常,您的代码中会有许多词法环境。但是所有的环境不会同时执行。我们很快就会看到这一点。
- 上下文-Context:将上下文这个词形象化的最好方法是,围绕你感兴趣的主题(或我们正在讨论的“上下文”)想一个圆圈(或包装)。上下文是围绕特定事件、情况等的一组情况或事实。
- 执行上下文-Execution Context:这意味着当前运行的代码和它周围的一切都有助于运行它。可以有很多可用的词法环境,但是,当前运行的环境由执行上下文管理。这里有一个图形演示来解释同样的情况,
执行上下文-Execution Context
作为软件开发人员,我们喜欢(或希望)编写代码,使其看起来不那么复杂,可以轻松维护,并遵循一些实践、标准等。用同样的类比,执行上下文 允许 JavaScript 引擎更好地维护代码并管理复杂性。
每当代码在 JavaScript 中运行时,它都会在 执行上下文 中运行。
全局执行上下文-Global Execution Context(GEC)
每当 JavaScript 代码首次运行时,它都会创建称为全局执行上下文(GEC)的东西。即使您在 .js 文件中没有一行代码并加载它,您也会创建全局执行上下文。
全局这个词在这里是什么意思?函数之外的任何东西都是全局的。
全局执行上下文也称为 基本执行上下文。它为您创建了两个特殊的东西,
- 用于浏览器的称为窗口的全局对象。如果您在服务器端使用 JavaScript,例如 NodeJs,它将不是窗口对象。
- 一个名为 this 的全局变量。
让我们通过几个例子来理解全局执行上下文
加载空脚本
每当 JavaScript 代码首次运行时,它都会创建称为全局执行上下文(GEC)的东西。即使您在 .js 文件中没有一行代码并加载它,您也会创建全局执行上下文。
全局这个词在这里是什么意思?函数之外的任何东西都是全局的。
全局执行上下文也称为 基本执行上下文。它为您创建了两个特殊的东西
- 用于浏览器的称为窗口的全局对象。如果您在服务器端使用 JavaScript,例如 NodeJs,它将不是窗口对象。
- 一个名为 this 的全局变量。
让我们通过几个例子来理解 全局执行上下文
加载空脚本
为简单起见,让我们取一个名为 index.js 的空 JavaScript 文件,并将其导入一个名为 index.html 的 html 文件中,如下所示
<html>
<head>
<script src="index.js" />
</head>
<body> I have loaded an empty Script </body>
</html>
一旦你在浏览器上加载了这个超文本标记语言,就不会有任何 JavaScript 代码被加载和执行。如果你打开调试器控制台(Chrome 为 F12)并输入这个,你会看到已经为你创建了一个叫做 this 的东西。
也可以尝试键入 Window,这次您将打印窗口对象值
是否注意到,窗口对象和 this 变量在 全局执行上下文 中都是相等的?试试这个来确认,
全局执行上下文,当它在没有任何 JavaScript 代码的情况下创建时,可以可视化为
使用变量和函数
现在让我们向 JavaScript 文件添加一些代码。我们添加了一个名为 name 的变量,并使用值 Tom 对其进行初始化。我们添加了一个名为 sayName() 的函数,它记录 name。
var name = 'Tom';
function sayName() {
console.log(this.name);
}
你认为 全局执行上下文 现在会发生什么变化?让我们先在下面的图形演示中看到它,然后解释如下。
全局执行上下文阶段
-
在全局执行上下文中创建了两个阶段,即创建和执行阶段。
-
创建阶段:
- 在这个阶段,创建了两个特殊的东西,即浏览器的全局对象
window和一个名为 this 的变量。 - 为变量
name和函数sayName()分配内存。 - 变量
name由一个名为undefined的特殊值初始化。函数sayName()直接放入内存中。
- 在这个阶段,创建了两个特殊的东西,即浏览器的全局对象
-
执行阶段:
- 在这个阶段,实际的代码执行开始了。对于上面的例子,唯一要做的就是将值 Tom 分配给变量
name。请注意,我们没有调用函数sayName(),尽管我们已经定义了它。但这个函数不会被执行。我们将在下一节中了解函数执行。
- 在这个阶段,实际的代码执行开始了。对于上面的例子,唯一要做的就是将值 Tom 分配给变量
函数执行上下文-Function Execution Context(FEC)
调用函数时会创建函数执行上下文
让我们看下面的例子来理解这个概念。在这个例子中,我们有一个名为 name 的全局变量,它被赋值为 Tom。我们有一个名为 tom() 的函数,它记录名称。最后,我们调用函数 tom()
var name = 'Tom';
function tom() {
console.log(this.name + ' Runs');
}
tom();
请参阅以下演示以同时理解函数执行上下文和全局执行上下文。
- 正如我们在上面看到的,全局执行上下文的创建阶段创建 window 对象、this 变量以及变量和函数的内存。变量用一个名为 undefined 的特殊值初始化。执行阶段将值分配给变量并调用函数。接下来,创建函数执行上下文。
- 函数执行上下文经历相同的阶段,创建和执行。需要注意的重要一点是,函数执行上下文可以访问一个名为 arguments 的特殊变量,这是在调用函数时传递给函数的参数。在我们的示例中,我们不传递任何参数。因此长度为 0。
- 一个函数可以调用另一个函数,也可以调用另一个函数,依此类推。对于每个函数调用,都会创建一个函数执行上下文。