搜尋
首頁web前端js教程JS — 理解 JavaScript 中的詞法環境 — 深入探究 — 第 1 部分

身為開發人員,我經常遇到「詞法環境」這個術語,但我從未真正花時間去全面深入地探索它。因此,我決定深入研究並在這篇文章中記錄我的發現 - 因為「分享就是關懷;)」。在這篇文章的結尾,我希望我們都能對詞法環境有一個深入的了解,並且我們還將探索記憶體中發生的情況、資料結構是什麼以及呼叫堆疊如何運作。別擔心 - 我會保持簡單明了!

詞彙環境

在深入了解細節之前,先簡單概述一下。如果有些概念一開始看起來很複雜,請不要擔心 - 我會將它們分解並使用類比來使它們更容易理解。

詞法環境是 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 區塊作用域。為了讓這些概念更容易理解,讓我們用羊做一個簡單的比喻:

羊的比喻:

本週在外面散步時,我在圍欄區域內遇到了一些羊,我想,「嘿,這就像一個詞彙環境!」

讓我解釋一下:想像一個有圍欄的區域,裡面有羊。羊隻能在圍欄內做事,例如吃草。現在,想像柵欄內有個小羊舍,小羊可以在那裡停留。屋內的羊不能出去,但屋外的羊可以進去。

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

打破類比:

柵欄代表一切存在的整個區域 - 綿羊、小羊、房子和草。這個圍欄區域就是我們所說的全域範圍。在這個圍欄區域內,羊舍是一個較小的、獨立的部分,代表一個街區範圍。最後,羊吃的草(yumyum)就像全局範圍內的一個函數,是羊可以在該空間內執行的特定活動或動作。

在程式碼區塊中,全域作用域以紅色框表示,drinkWater函數作用域以藍色框表示,if區塊作用域以綠色框表示。這是三個詞彙環境。

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

全球範圍(圍欄區域):

羊(以varsheep = 1;表示)象徵全局範圍內的變量,在圍欄區域自由漫遊。它可以在 DrinkWater 函數和 if 區塊的外部和內部使用。

功能範圍(喝水):

drinkWater 函數代表羊可以在圍欄區域內執行的動作。我們可以從全域範圍內的任何地方呼叫 DrinkWater 函數。然而,函數本身在定義時會創造一個新的詞法環境。在這個函數內部,變數(例如 let waterTemperature = 'cold';)只能在函數內部存取。

區塊範圍(如果是區塊):

if 區塊建立了一個新的、更小的作用域。在這個以羊舍為代表的範圍內,有 2 隻羔羊(設羔羊 = 2)。在此作用域內,console.log 語句記錄羔羊變數以及全域綿羊變數的值。 Lambs 變數特定於區塊作用域,而 Sheep 變數是從父環境(全域作用域)取得的。這是透過外部環境引用實現的,它允許 JavaScript 查找作用域鏈並解析當前環境中找不到的變數。

外在環境引用是詞法環境中的引用或指標。它指向父詞法環境,允許 JavaScript 透過尋找作用域鏈來解析在當前環境中找不到的變數。

提問時間!

您可以修改 DrinkWater() 函數,以便它記錄全域範圍內定義的可以喝水的羊總數嗎?在留言區分享你的答案吧!

理解多重詞彙環境

因此,我們看到這段程式碼中存在三個詞法環境:全域作用域、函數作用域和區塊作用域。當存在多個詞彙環境時,我們稱之為多個詞彙環境。理解單段程式碼中可以存在多個詞法環境非常重要。每次建立新作用域(例如,函數或區塊)時,都會產生新的詞法環境,這意味著程式碼的不同部分可以擁有自己單獨的環境。

環境記錄

現在我們了解了詞法環境的工作原理,讓我們更深入地了解環境記錄的概念。

每當建立詞法環境時 - 無論是全域範圍、函數或區塊 - JavaScript 都會自動為其產生環境記錄。

此環境記錄是一種資料結構,用於追蹤該特定範圍內可存取的所有變數、函數和其他綁定。本質上,它充當該環境中定義的所有內容的內部存儲,確保在程式碼執行期間需要時提供正確的資料。

詞彙環境和環境記錄的區別

詞法環境和環境記錄之間的主要區別:

詞法環境是 JavaScript 程式碼運作的地方。將其視為代碼所在的“設定”或“上下文”。此上下文包括變數和函數的範圍,確定哪些變數和函數在程式碼中的任何點可用或可存取。例如,在我們的程式碼中,羔羊變數只能在綠色邊框環境(區塊作用域)內存取。詞法環境還包括外部環境引用(我們已經描述過),允許存取父環境中的變數。

環境記錄是詞法環境中的特定儲存區域,它保存該環境中使用的實際變數、函數宣告和其他識別碼。雖然詞法環境是更廣泛的上下文,但環境記錄是儲存程式碼資料(例如變數值和函數定義)的位置。每當 JavaScript 需要存取變數或函數時,它都會尋找當前詞法環境的環境記錄。

讓我們使用我們的程式碼範例再次解釋一下詞法環境和環境記錄:

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

共有三個詞法環境,每個都有自己的環境記錄:

  1. 全域範圍(紅框),詞法環境 1: 這個詞彙環境是在全局層級創建的。此環境中的環境記錄包含:
    • 可變的羊。
    • 函數喝水。
    • 變數sheepHouseInArea。

這些聲明可以在整個程式碼中存取。全域環境也引用了在此環境中定義的函數 DrinkWater 以及 if 語句,該語句在執行時會建立自己的區塊作用域。

  1. 函數範圍(drinkWater,藍色框),詞法環境 2:
    此環境中的環境記錄包含變數 waterTemperature,該變數在 DrinkWater 函數中使用 let 進行宣告。該變數只能在函數內存取。然而,該函數也可以像sheep一樣存取全域環境中的變數。

  2. 區塊範圍(如果是區塊,則為綠色框),詞法環境 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.

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

以上是JS — 理解 JavaScript 中的詞法環境 — 深入探究 — 第 1 部分的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
JavaScript是用C編寫的嗎?檢查證據JavaScript是用C編寫的嗎?檢查證據Apr 25, 2025 am 12:15 AM

是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

JavaScript的角色:使網絡交互和動態JavaScript的角色:使網絡交互和動態Apr 24, 2025 am 12:12 AM

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C和JavaScript:連接解釋C和JavaScript:連接解釋Apr 23, 2025 am 12:07 AM

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

從網站到應用程序:JavaScript的不同應用從網站到應用程序:JavaScript的不同應用Apr 22, 2025 am 12:02 AM

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python vs. JavaScript:比較用例和應用程序Python vs. JavaScript:比較用例和應用程序Apr 21, 2025 am 12:01 AM

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C/C在JavaScript口譯員和編譯器中的作用C/C在JavaScript口譯員和編譯器中的作用Apr 20, 2025 am 12:01 AM

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

JavaScript在行動中:現實世界中的示例和項目JavaScript在行動中:現實世界中的示例和項目Apr 19, 2025 am 12:13 AM

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具