”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > JS — 理解 JavaScript 中的词法环境 — 深入探究 — 第 1 部分

JS — 理解 JavaScript 中的词法环境 — 深入探究 — 第 1 部分

发布于2024-11-08
浏览:410

As a developer, I have often encountered the term "lexical environment" but I never really took the time to fully explore it in depth. So, I decided to dive deep and document my findings in this post - because "sharing is caring ;)". By the end of this post, I hope we will both have a solid understanding of what a lexical environment is and we will also explore what happens in memory, what a data structure is, and how the call stack works. Don't worry - I'll keep it simple and clear!

The Lexical Environment

Before diving into the details, let me start with a brief overview. Don't worry if some concepts seem complex at first - I'll break them down and use an analogy to make them easier to understand.

A lexical environment is a special data structure in JavaScript that tracks the scope of variables and functions at a specific point in the code.

Data structures are ways to organize and store information in a computer so it can be used efficiently. Common examples include arrays, objects, lists, and trees. See more: Data Structures Tutorial - GeeksforGeeks

The term "lexical" means that the scope and accessibility of variables and functions are determined by where they are written in the code, rather than how the program runs.

Key roles of a lexical environment:

  • It stores all variables and function declarations within a specific scope (such as a function or a block).
  • It makes these stored items accessible at that particular point in your code.

Here's a simple code example that contains three different lexical environments:

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);

The three lexical environments in this code are: the global scope, the drinkWater function scope, and the if block scope. To make these concepts easier to grasp, let's use a simple analogy involving sheep:

The Sheep Analogy:

While walking outside this week, I came across some sheep inside a fenced area and thought, "Hey, this is like a lexical environment!"

Let me explain: Imagine a fenced area with sheep inside. The sheep can only do things within the fence, like eating grass. Now, imagine there's a small sheep house inside the fence where lambs can stay. The lambs inside the house can't go outside, but the sheep outside can go in.

JS — Understanding Lexical Environments in JavaScript — Deep Dive — Part 1

Breaking Down the Analogy:

The fence represents the entire area where everything exists - the sheep, lambs, house, and grass. This fenced area is what we refer to as the global scope. Within this fenced area, the sheep house is a smaller, separate section, representing a block scope. Finally, the grass which the sheep eat (yumyum) is like a function within the global scope, a specific activity or action that the sheep can perform within that space.

In the code block, the global scope is represented by the red box, the drinkWater function scope by the blue box, and the if block scope by the green box. These are the three lexical environments.

JS — Understanding Lexical Environments in JavaScript — Deep Dive — Part 1

Global Scope (Fenced Area):

The sheep (represented by var sheep = 1;) symbolizes a variable in the global scope, freely roaming the fenced area. It can be used both outside and inside the drinkWater function and the if block.

Function Scope (drinkWater):

The drinkWater function represents an action the sheep can perform within the fenced area. We can call the drinkWater function from anywhere in the global scope. However, the function itself creates a new lexical environment when it's defined. Inside this function, variables (like let waterTemperature = 'cold';) are only accessible within the function.

Block Scope (if block):

The if block creates a new, smaller scope. In this scope, represented by the sheep house, there are 2 lambs (let lambs = 2). Inside this scope, a console.log statement logs the value of the lambs variable as well as the global sheep variable. The lambs variable is specific to the block scope, while the sheep variable is fetched from the parent environment (the global scope). This is made possible by the Outer Environment Reference, which allows JavaScript to look up the scope chain and resolve variables not found in the current environment.

The Outer Environment Reference is a reference or a pointer within a lexical environment. It points to the parent lexical environment, allowing JavaScript to resolve variables that aren't found in the current environment by looking up the scope chain.

Question Time!

Can you modify the drinkWater() function so that it logs the total number of sheep defined in the global scope that can drink the water? Share your answer in the comments section!

Understanding Multiple Lexical Environments

So, we see that there are three lexical environments in this code: the global scope, the function scope, and the block scope. When there is more than one lexical environment, we call it multiple lexical environments. It's important to understand that multiple lexical environments can exist in a single piece of code. Each time a new scope is created (e.g., a function or a block), a new lexical environment is generated, meaning different parts of your code can have their own separate environments.

The Environment Record

Now that we understand how lexical environments work, let's dive deeper into the concept of the environment record.

Whenever a lexical environment is created - whether it's for the global scope, a function, or a block - JavaScript automatically generates an environment record for it.

This environment record is a data structure that keeps track of all the variables, functions, and other bindings that are accessible within that specific scope. Essentially, it acts as the internal storage for everything defined within that environment, ensuring that the correct data is available when needed during code execution.

Difference Between Lexical Environment and Environment Record

The key difference between a lexical environment and an environment record:

A lexical environment is the place where JavaScript code runs. Think of it as the "setting" or "context" in which your code exists. This context includes the scope of variables and functions, determining which ones are available or accessible at any point in the code. For example, in our code, the lambs variable is only accessible within the green-bordered environment (the block scope). A lexical environment also includes an Outer Environment Reference (which we already described), allowing access to variables in parent environments.

An environment record is a specific storage area within a lexical environment that holds the actual variables, function declarations, and other identifiers used in that environment. While the lexical environment is the broader context, the environment record is where the code's data - like variable values and function definitions - is stored. Whenever JavaScript needs to access a variable or function, it looks in the environment record of the current lexical environment.

Let's explain the lexical environment and environment record again using our code example:

JS — Understanding Lexical Environments in JavaScript — Deep Dive — Part 1

There are three lexical environments, each with its own environment record:

  1. Global Scope (red box), Lexical Environment 1: This lexical environment is created at the global level. The environment record within this environment contains:
    • The variable sheep.
    • The function drinkWater.
    • The variable sheepHouseInArea.

These declarations are accessible throughout the entire code. The global environment also references the function drinkWater, which is defined in this environment, and the if statement, which leads to the creation of its own block scope when executed.

  1. Function Scope (drinkWater, blue box), Lexical Environment 2:
    The environment record in this environment contains the variable waterTemperature, declared using let inside the drinkWater function. This variable is only accessible within the function. However, the function can also access variables in the global environment like sheep.

  2. Block Scope (if block, green box), Lexical Environment 3:
    The environment record within this environment contains the variable lambs, declared using let inside the if block. This variable is only accessible within this specific block scope. The block can also access variables from its parent environment, such as sheep and sheepHouseInArea.

What Happens Behind the Scenes in Memory

After diving deep into lexical environments and environment records, we're now ready to understand how JavaScript manages memory and variable access during code execution.

When your code runs, JavaScript creates a new lexical environment for each function or block of code. Each environment has its own environment record, storing all the variables and functions defined in that scope. This setup ensures efficient memory usage, as we've discussed.

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.

JS — Understanding Lexical Environments in JavaScript — Deep Dive — Part 1

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');
  1. main() (global execution context)
  2. processUser('Alice')
  3. 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:

  1. 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.
  2. Scope Chains: We'll explore how JavaScript navigates through nested environments to find variables, like a treasure hunt in your code.
  3. 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

版本声明 本文转载于:https://dev.to/nuri/js-understanding-lexical-environments-in-javascript-deep-dive-part-1-417a?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 如何在 PHP 中从子域中提取域名?
    如何在 PHP 中从子域中提取域名?
    在 PHP 中从子域中提取域名在当代 Web 开发中,必须解析和检索域名,甚至是从子域中解析和检索域名。一个简单的示例可能包括诸如“here.example.com”或“example.org”之类的域名。为了满足这一需求,我们提出了一个全面的 PHP 函数,旨在从任何给定的输入中提取根域名。结合使...
    编程 发布于2024-11-08
  • 如何在多线程编程中连接向量以获得最佳效率?
    如何在多线程编程中连接向量以获得最佳效率?
    连接向量:深入分析在多线程编程中,合并结果是一个常见的挑战。这通常涉及将多个向量组合成单个综合向量。让我们探索连接向量以获得最大效率的最佳方法。最佳连接方法为了高效的向量连接,最佳实践是利用保留和插入方法:AB.reserve(A.size() B.size()); // Preallocate...
    编程 发布于2024-11-08
  • 如何优化FastAPI以实现高效的JSON数据返回?
    如何优化FastAPI以实现高效的JSON数据返回?
    FastAPI 返回大型 JSON 数据的优化通过 FastAPI 返回大量 JSON 数据集可能是一项耗时的任务。为了解决这个瓶颈,我们探索提高性能的替代方法。识别瓶颈:使用 json.dumps 将 Parquet 文件解析为 JSON 的初始方法( ) 和 json.loads() 效率低下。...
    编程 发布于2024-11-08
  • React:状态 X 派生状态
    React:状态 X 派生状态
    什么是派生状态?考虑文本的一种状态,然后考虑大写文本的另一种状态。 导出状态 function Foo() { const [text, setText] = useState('hello, za warudo!'); const [uppercaseText, s...
    编程 发布于2024-11-08
  • 如何使用自定义用户类型将 PostgreSQL JSON 列映射到 Hibernate 实体?
    如何使用自定义用户类型将 PostgreSQL JSON 列映射到 Hibernate 实体?
    将 PostgreSQL JSON 列映射到 Hibernate 实体使用 PostgreSQL 数据库时,经常会遇到以 JSON 格式存储数据的列。为了使用 Hibernate 有效地将这些列映射到 Java 实体,选择适当的数据类型至关重要。在这种情况下,当前的问题围绕着将 PostgreSQL...
    编程 发布于2024-11-08
  • 确保整个团队的 Node.js 版本一致
    确保整个团队的 Node.js 版本一致
    .nvmrc 和 package.json 综合指南 在当今动态的开发环境中,跨不同项目管理多个 Node.js 版本通常是一项复杂且容易出错的任务。 Node.js 版本不一致可能会导致许多问题,从意外行为到应用程序完全失败。 利用 .nvmrc 文件进行版本控制 在项目中保持一致...
    编程 发布于2024-11-08
  • 何时在 JavaScript Promise 中使用 Promise.reject 与 Throw?
    何时在 JavaScript Promise 中使用 Promise.reject 与 Throw?
    JavaScript Promise:Reject 与 Throw 之谜使用 JavaScript Promise 时,开发人员经常面临一个困境:他们是否应该使用 Promise .reject 或者只是抛出一个错误?虽然这两种方法具有相似的目的,但关于它们的差异和潜在优势仍然存在混淆。探索相似之处...
    编程 发布于2024-11-08
  • 构建 Chrome 扩展:快速概述
    构建 Chrome 扩展:快速概述
    模组——修改? 如果您喜欢游戏,您就会知道没有什么比玩模组游戏更好的了。这是您最喜欢的游戏,但具有额外的功能、功能和乐趣。现在,想象一下为您的网络浏览体验带来同样的兴奋。这正是浏览器扩展的作用——它们就像浏览器的模组,以您从未想过的方式增强浏览器的功能。 通过 Chrome 扩展程序,您可以调整浏览...
    编程 发布于2024-11-08
  • 如何使用 CSS 设置表格列宽?
    如何使用 CSS 设置表格列宽?
    设置表格列宽表格通常用于呈现表格数据,但调整列宽对于确保可读性和正确性至关重要结盟。在本文中,我们将探讨如何使用 CSS 设置表格列的宽度。使用 CSS 宽度属性的方法表格列的宽度可以使用 col 元素的 width 属性进行设置。宽度值可以以像素为单位指定(例如 width: 200px;),也可...
    编程 发布于2024-11-08
  • 如何从 Python 中的嵌套函数访问非局部变量?
    如何从 Python 中的嵌套函数访问非局部变量?
    访问嵌套函数作用域中的非局部变量在 Python 中,嵌套函数作用域提供对封闭作用域的访问。但是,尝试修改嵌套函数内封闭范围内的变量可能会导致 UnboundLocalError。要解决此问题,您有多种选择:1。使用 'nonlocal' 关键字 (Python 3 ):对于 Pyt...
    编程 发布于2024-11-08
  • 使用 CSS 将渐变应用于文本。
    使用 CSS 将渐变应用于文本。
    文字渐变 现在你可以在很多地方看到像文本渐变这样的好技巧......但是呢?你有没有想过它们是如何制作的?今天就让我来教你吧。 .text-gradient { background: linear-gradient(-25deg, #5662f6 0%, #7fffd4 10...
    编程 发布于2024-11-08
  • 如何在Python中执行自定义区间舍入?
    如何在Python中执行自定义区间舍入?
    Python 中舍入为自定义间隔在 Python 中,内置 round() 函数通常用于对数值进行舍入。然而,它采用以 10 为基数的舍入方案,这可能并不总是适合特定要求。例如,如果您想将数字四舍五入到最接近的 5 倍数,则标准 round() 函数不合适。要解决此问题,可以创建一个自定义函数,将值...
    编程 发布于2024-11-08
  • 项目 注意字符串连接性能
    项目 注意字符串连接性能
    1。使用运算符 ( ) 连接字符串: 使用运算符连接字符串对于少量连接来说很方便,但由于字符串的不变性,在大规模操作时会出现性能问题。 每次创建新字符串时,都会复制所有先前字符串的内容,从而导致大型连接的时间成二次方。 不正确的示例(与 重复连接): public String criaFatura...
    编程 发布于2024-11-08
  • 如何解决 Wamp 服务器中的橙色图标问题:识别服务故障并对其进行故障排除
    如何解决 Wamp 服务器中的橙色图标问题:识别服务故障并对其进行故障排除
    解决 Wamp Server 中顽固的橙色图标在 Web 开发领域,WampServer 图标旁边出现橙色图标可以成为令人沮丧的路障。此持久图标通常表示启动 Apache 或 MySQL 服务失败,使您陷入开发困境。识别罪魁祸首:Apache 或 MySQL?确定哪个服务导致了问题,单击 wampm...
    编程 发布于2024-11-08
  • 网络基础知识
    网络基础知识
    In the world of system design, networks are the glue that binds different components together. Whether you're building a web application, a distribute...
    编程 发布于2024-11-08

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3