作为一名开发人员,我经常遇到“词法环境”这个术语,但我从未真正花时间去全面深入地探索它。因此,我决定深入研究并在这篇文章中记录我的发现 - 因为“分享就是关怀;)”。在这篇文章的结尾,我希望我们都能对词法环境有一个深入的了解,并且我们还将探索内存中发生的情况、数据结构是什么以及调用堆栈如何工作。别担心 - 我会保持简单明了!
词汇环境
在深入了解细节之前,让我先简要概述一下。如果有些概念一开始看起来很复杂,请不要担心 - 我会将它们分解并使用类比来使它们更容易理解。
词法环境是 JavaScript 中的一种特殊数据结构,用于跟踪代码中特定点的变量和函数的范围。
数据结构是在计算机中组织和存储信息以便有效使用信息的方法。常见示例包括数组、对象、列表和树。查看更多:数据结构教程 - GeeksforGeeks
术语“词法”意味着变量和函数的范围和可访问性取决于它们在代码中的编写位置,而不是程序的运行方式。
词汇环境的关键角色:
- 它存储特定范围(例如函数或块)内的所有变量和函数声明。
- 它使这些存储的项目可以在代码中的特定点访问。
这是一个简单的代码示例,其中包含三种不同的词法环境:
var sheep = 1; // Global sheep function drinkWater() { let waterTemperature = "cold"; console.log("The sheep is drinking " + waterTemperature + " water."); } var sheepHouseInArea = true; // Indicates whether the sheep house is present if (sheepHouseInArea) { let lambs = 2; // Lambs inside the house console.log("There are " + sheep + " sheep in the total area and " + lambs + " lambs!"); } // This will result in an error because 'lambs' // is only accessible inside the if block! console.log("How many lambs are there? " + lambs);
此代码中的三个词法环境是:全局作用域、drinkWater 函数作用域和 if 块作用域。为了让这些概念更容易理解,让我们用羊做一个简单的比喻:
羊的比喻:
本周在外面散步时,我在围栏区域内遇到了一些羊,我想,“嘿,这就像一个词汇环境!”
让我解释一下:想象一个有围栏的区域,里面有羊。羊只能在围栏内做事,比如吃草。现在,想象一下栅栏内有一个小羊舍,小羊可以在那里停留。屋内的羊不能出去,但屋外的羊可以进去。
打破类比:
栅栏代表一切存在的整个区域 - 绵羊、小羊、房子和草。这个围栏区域就是我们所说的全局范围。在这个围栏区域内,羊舍是一个较小的、独立的部分,代表一个街区范围。最后,羊吃的草(yumyum)就像全局范围内的一个函数,是羊可以在该空间内执行的特定活动或动作。
在代码块中,全局作用域由红色框表示,drinkWater函数作用域由蓝色框表示,if块作用域由绿色框表示。这是三个词汇环境。
全球范围(围栏区域):
羊(用varsheep = 1;表示)象征着全局范围内的变量,在围栏区域自由漫游。它可以在 DrinkWater 函数和 if 块的外部和内部使用。
功能范围(喝水):
drinkWater 函数代表羊可以在围栏区域内执行的动作。我们可以从全局范围内的任何地方调用 DrinkWater 函数。然而,函数本身在定义时会创建一个新的词法环境。在这个函数内部,变量(比如 let waterTemperature = 'cold';)只能在函数内部访问。
块范围(如果是块):
if 块创建了一个新的、更小的作用域。在以羊舍为代表的这个范围内,有 2 只羔羊(设羔羊 = 2)。在此作用域内,console.log 语句记录羔羊变量以及全局绵羊变量的值。 Lambs 变量特定于块作用域,而 Sheep 变量是从父环境(全局作用域)获取的。这是通过外部环境引用实现的,它允许 JavaScript 查找作用域链并解析当前环境中找不到的变量。
外部环境引用是词法环境中的引用或指针。它指向父词法环境,允许 JavaScript 通过查找作用域链来解析在当前环境中找不到的变量。
提问时间!
您可以修改 DrinkWater() 函数,以便它记录全局范围内定义的可以喝水的羊总数吗?在评论区分享你的答案吧!
理解多重词汇环境
因此,我们看到这段代码中存在三个词法环境:全局作用域、函数作用域和块作用域。当存在多个词汇环境时,我们将其称为多个词汇环境。理解单段代码中可以存在多个词法环境非常重要。每次创建新作用域(例如,函数或块)时,都会生成新的词法环境,这意味着代码的不同部分可以拥有自己单独的环境。
环境记录
现在我们了解了词法环境的工作原理,让我们更深入地了解环境记录的概念。
每当创建词法环境时 - 无论是全局范围、函数还是块 - JavaScript 都会自动为其生成环境记录。
此环境记录是一种数据结构,用于跟踪该特定范围内可访问的所有变量、函数和其他绑定。本质上,它充当该环境中定义的所有内容的内部存储,确保在代码执行期间需要时提供正确的数据。
词汇环境和环境记录之间的区别
词法环境和环境记录之间的主要区别:
词法环境是 JavaScript 代码运行的地方。将其视为代码所在的“设置”或“上下文”。此上下文包括变量和函数的范围,确定哪些变量和函数在代码中的任何点可用或可访问。例如,在我们的代码中,羔羊变量只能在绿色边框环境(块作用域)内访问。词法环境还包括外部环境引用(我们已经描述过),允许访问父环境中的变量。
环境记录是词法环境中的特定存储区域,它保存该环境中使用的实际变量、函数声明和其他标识符。虽然词法环境是更广泛的上下文,但环境记录是存储代码数据(例如变量值和函数定义)的位置。每当 JavaScript 需要访问变量或函数时,它都会查找当前词法环境的环境记录。
让我们使用我们的代码示例再次解释一下词法环境和环境记录:
共有三个词法环境,每个都有自己的环境记录:
- 全局范围(红框),词法环境 1:
这个词汇环境是在全局级别创建的。该环境中的环境记录包含:
- 可变的羊。
- 函数喝水。
- 变量sheepHouseInArea。
这些声明可以在整个代码中访问。全局环境还引用了在此环境中定义的函数 DrinkWater 以及 if 语句,该语句在执行时会创建自己的块作用域。
函数范围(drinkWater,蓝色框),词法环境 2:
该环境中的环境记录包含变量 waterTemperature,该变量在 DrinkWater 函数中使用 let 进行声明。该变量只能在函数内访问。然而,该函数也可以像sheep一样访问全局环境中的变量。块范围(如果是块,则为绿色框),词法环境 3:
该环境中的环境记录包含变量羔羊,在 if 块内使用 let 进行声明。该变量只能在该特定块作用域内访问。该块还可以访问其父环境中的变量,例如sheep和sheepHouseInArea。
记忆中幕后发生的事情
深入研究词法环境和环境记录后,我们现在准备好了解 JavaScript 在代码执行期间如何管理内存和变量访问。
当您的代码运行时,JavaScript 会为每个函数或代码块创建一个新的词法环境。每个环境都有自己的环境记录,存储在该范围内定义的所有变量和函数。正如我们所讨论的,此设置可确保高效的内存使用。
Behind the scenes, the JavaScript engine handles these lexical environments in memory. The call stack is used for tracking function calls, while block scopes create new lexical environments linked to their outer environments. However, unlike functions, these block scopes aren't pushed onto the call stack.
What is the call stack?
The call stack is a fundamental concept in how Javascript executes code.
The call stack is a data structure that keeps track of function calls in a program. It works on a Last-In-First-Out (LIFO) principle. Here's how it works:
- When a function is called, it's added (pushed) to the top of the stack.
- When a function finishes executing, it's removed (popped) from the top of the stack.
- The stack also keeps track of the current position in the code.
Key points about the call stack:
- It records where in the program we are.
- If we step into a function, we put it on the top of the stack.
- If we return from a function, we pop it off the stack.
- The stack has a maximum size, and if that limit is exceeded, it results in a "stack overflow" error.
Now you know why its called stack overflow haha!
Here's a simple example to illustrate:
function greet(name) { console.log('Hello, ' + name); } function processUser(user) { greet(user); } processUser('Alice');
- main() (global execution context)
- processUser('Alice')
- greet('Alice')
As each function completes, it's popped off the stack until we return to the global context.
The last final question!
In our sheep code example, can you identify if anything is placed on the call stack during execution? Share your thoughts in the comments section!
Conclusion
That's it for Part 1! I hope this post has helped you gain a solid understanding of how JavaScript handles lexical environments, environment records, and what happens behind the scenes in memory. I've learned a lot in the process, and I hope you have too. If you have any questions or feedback, I'd love to hear from you - let's learn and improve together!
I titled this post 'Part 1' because I plan to follow up with 'Part 2,' where I'll dive into three major concepts that are closely linked to lexical environments:
- Closures: Think of them as magical boxes that let functions remember and access variables from their outer environment, even after the outer function has finished executing.
- Scope Chains: We'll explore how JavaScript navigates through nested environments to find variables, like a treasure hunt in your code.
- Hoisting: This explains why some variables and functions seem to "float" to the top of their scope, which can be tricky to understand but is crucial for writing predictable code.
These concepts are super important because they directly impact how your JavaScript code behaves. Understanding them will help you write cleaner, more efficient code and avoid some common pitfalls.
Stay tuned!
--
Please also follow me on my Medium: https://medium.com/@ensing89
以上是JS — 理解 JavaScript 中的词法环境 — 深入探究 — 第 1 部分的详细内容。更多信息请关注PHP中文网其他相关文章!

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

JavaScript是现代Web开发的基石,它的主要功能包括事件驱动编程、动态内容生成和异步编程。1)事件驱动编程允许网页根据用户操作动态变化。2)动态内容生成使得页面内容可以根据条件调整。3)异步编程确保用户界面不被阻塞。JavaScript广泛应用于网页交互、单页面应用和服务器端开发,极大地提升了用户体验和跨平台开发的灵活性。

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。 1.Python以简洁语法和丰富库生态着称,适用于数据分析和Web开发。 2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

JavaScript不需要安装,因为它已内置于现代浏览器中。你只需文本编辑器和浏览器即可开始使用。1)在浏览器环境中,通过标签嵌入HTML文件中运行。2)在Node.js环境中,下载并安装Node.js后,通过命令行运行JavaScript文件。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

Atom编辑器mac版下载
最流行的的开源编辑器

SecLists
SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

DVWA
Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

SublimeText3 Linux新版
SublimeText3 Linux最新版

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能