」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > JS — 理解 JavaScript 中的詞法環境 — 深入探究 — 第 1 部分

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

發佈於2024-11-08
瀏覽:614

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]刪除
最新教學 更多>
  • 如何從 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(Li...
    程式設計 發佈於2024-11-08
  • 如何解決 Wamp 伺服器中的橘色圖示問題:識別服務故障並對其進行故障排除
    如何解決 Wamp 伺服器中的橘色圖示問題:識別服務故障並對其進行故障排除
    解決Wamp Server 中頑固的橙色圖標解決Wamp Server 中頑固的橙色圖標在Web 開發領域,WampServer 圖標旁邊出現橙色圖標可以成為令人沮喪的橙色路障。此持久性圖示通常表示啟動 Apache 或 MySQL 服務失敗,使您陷入開發困境。 識別罪魁禍首:Apache 或 My...
    程式設計 發佈於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
  • Python 初學者教學:學習基礎知識
    Python 初學者教學:學習基礎知識
    欢迎来到Python编程的奇妙世界!如果您是编码新手,请系好安全带,因为 Python 是最简单但最强大的语言之一。无论您是想自动执行繁琐的任务、构建 Web 应用程序还是深入研究数据科学,Python 都是您成功编码的门户。 在本初学者指南中,我们将引导您完成 Python 的基本构建块,确保您准...
    程式設計 發佈於2024-11-08
  • 如何提取MySQL字串中第三個空格之後的子字串?
    如何提取MySQL字串中第三個空格之後的子字串?
    MySQL:提取字串中的第三個索引要使用MySQL 定位字串中第三個空格的索引,一種方法是利用SUBSTRING_INDEX 函數。此函數可以提取直到指定分隔符號(在本例中為空格字元)的子字串。 要隔離第三個空格,您可以使用兩個巢狀的 SUBSTRING_INDEX 呼叫。內部函數呼叫檢索從字串開頭...
    程式設計 發佈於2024-11-08
  • 如果無法存取已指派的空間,為什麼要為 ArrayList 設定初始大小?
    如果無法存取已指派的空間,為什麼要為 ArrayList 設定初始大小?
    了解 ArrayList 中的初始大小在 Java 中,ArrayList 是動態數組,可以根據需要增長和縮小。可以使用建構子 new ArrayList(10) 指定 ArrayList 的初始大小,其中 10 表示所需的容量。 但是,設定初始大小並未授予立即存取已指派空間的權限。與傳統陣列不同,...
    程式設計 發佈於2024-11-08
  • 如何在不改變系統設定的情況下使Python 2.7成為Linux中的預設版本?
    如何在不改變系統設定的情況下使Python 2.7成為Linux中的預設版本?
    Linux 中的預設 Python 版本:選擇 Python 2.7在 Linux 系統上運行多個 Python 版本是常見的情況。然而,瀏覽預設版本有時可能會很困難。本文討論如何在終端機上鍵入「python」命令時將 Python 2.7 設為預設版本。 預設 Python 更改的評估更改預設 P...
    程式設計 發佈於2024-11-08
  • 如何根據多個條件對 Go 中具有嵌套切片的結構切片進行排序?
    如何根據多個條件對 Go 中具有嵌套切片的結構切片進行排序?
    使用嵌套切片對結構體切片進行排序在Go 中,您可以使用內建的排序包對自訂結構體切片進行排序。考慮以下程式碼,它定義了兩個結構體 Parent 和 Child,表示父子關係:type Parent struct { id string children []Child } ...
    程式設計 發佈於2024-11-08
  • C# | Web Api 的提示和技巧
    C# | Web Api 的提示和技巧
    筆記 您可以查看我個人網站上的其他帖子:https://hbolajraf.net Web Api 的提示和技巧 用 C# 建立 Web API 是創建可擴展且高效的後端服務的強大方法。以下是一些提示和技巧,可協助您充分利用 C# Web API 開發。 1.使...
    程式設計 發佈於2024-11-08
  • JavaScript 模組
    JavaScript 模組
    現在我們不再將所有 JS 寫在一個文件中並發送給客戶端。 今天,我們將程式碼編寫到模組中,這些模組之間共享資料並且更易於維護。 約定是使用駝峰命名法命名模組。 我們甚至可以透過 npm 儲存庫將第 3 方模組包含到我們自己的程式碼中,例如 jquery、react、webpack、babel...
    程式設計 發佈於2024-11-08
  • 適合前端開發人員的最佳 JavaScript 框架
    適合前端開發人員的最佳 JavaScript 框架
    要開始您作為前端開發人員的旅程,選擇正確的 JavaScript 框架可以顯著影響您的學習曲線和專案成功。以下是每個前端開發人員都應該選擇的一些最佳 JavaScript 框架。 1. 反應 React 是一個廣泛使用的 JavaScript 函式庫,用於建立使用者介面,主要關注單...
    程式設計 發佈於2024-11-08
  • 如何在 Python 中停用 .pyc 檔案生成?
    如何在 Python 中停用 .pyc 檔案生成?
    如何阻止Python產生.pyc檔如何阻止Python產生.pyc檔Python通常將原始碼(.py檔)編譯為字節碼(.pyc檔)以提高執行速度。但是,您可能會遇到希望執行解釋器而不建立 .pyc 檔案的情況。 根據“What's New in Python 2.6 - Interprete...
    程式設計 發佈於2024-11-08

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3