JavaScript 閉包的魔力:清晰易懂的指南
JavaScript 中的閉包是什麼?
將閉合想像成您下課後隨身攜帶的背包。背包裡有你在課堂上學到的所有筆記和材料。即使課程結束後,您仍然可以在需要時使用背包中的所有物品。類似地,閉包允許函數保留對其外部作用域的變數和參數的訪問,即使在外部函數完成運行並且這些變數在該函數外部不再可訪問之後也是如此。
上面的解釋是描述閉包的典型方式,但是對於剛接觸 JavaScript 的人來說它適合初學者嗎?並不真地。當我第一次遇到它時,我也覺得很困惑。這就是為什麼我寫這篇文章是為了讓閉包盡可能簡單,讓任何人都能理解。我們將先介紹基礎知識,然後再深入探討這個主題。
理解 JavaScript 中的作用域
要理解什麼是閉包,我們必須簡單了解 JavaScript 中的作用域。範圍是指程式碼不同部分中變數和函數的可訪問性。它決定了我們可以在程式中存取某些變數或函數的位置。
作用域有兩種主要類型:全域作用域和局部作用域。在全域作用域中聲明的變數存在於任何函數或區塊之外,從而使它們可以在整個程式碼中存取。相反,在局部範圍內(例如在函數或區塊內)聲明的變數只能在該特定函數或區塊內存取。下面的程式碼說明了這個解釋。
// GLOBAL SCOPE let myName = "John Doe"; function globalScope() { console.log(myName); } globalScope(); //Output John Doe console.log(myName); // Accessible here as well // LOCAL SCOPE function localScope() { let age = 30; console.log(age); } localScope(); //Output 30 console.log(age); //Output age is not defined (Not Accessible)
然而,JavaScript 使用了一個稱為詞法作用域的概念,這對於理解閉包的工作原理至關重要。詞法作用域意味著變數的可訪問性由編寫程式碼時的結構決定。簡單來說,這就像在說:「如果在函數內聲明變量,則只有該函數及其中的任何內容都可以訪問該變量。」{https://javascript.info/closure}。
詞法範圍和執行上下文
為了更清楚地理解這一點,讓我們看看 JavaScript 在幕後是如何運作的。 JavaScript 使用稱為執行上下文的東西,它就像一個保存正在運行的程式碼的容器。它追蹤變數、函數以及目前正在運行的程式碼部分。當腳本啟動時,將建立全域執行上下文 (GEC)。需要注意的是,程式中只有一個全域執行上下文。
上圖代表了程式開始時的全域執行上下文。它由兩個階段組成:創建(或記憶體)階段和執行(或程式碼)階段。在創建階段,變數和函數儲存在記憶體中——變數被初始化為未定義,函數被完全儲存。在執行階段,JavaScript 逐行執行程式碼,為變數賦值並執行函數。
現在我們了解了 JavaScript 如何處理執行上下文和詞法作用域,我們可以看到它如何直接與閉包連結。
閉包如何運作:一個例子
當內部函數保留對其外部函數作用域中的變數的存取權時,即使外部函數已完成執行,也會建立 JavaScript 中的閉包。這是可能的,因為內部函數保留了定義它的詞法環境,允許它「記住」並使用外部作用域中的變數。
// GLOBAL SCOPE let myName = "John Doe"; function globalScope() { console.log(myName); } globalScope(); //Output John Doe console.log(myName); // Accessible here as well // LOCAL SCOPE function localScope() { let age = 30; console.log(age); } localScope(); //Output 30 console.log(age); //Output age is not defined (Not Accessible)
這是有關上述程式碼如何運作的指南。每當我們呼叫函數時,JavaScript 引擎都會建立一個特定於該函數的函數執行上下文 (FEC),該函數執行上下文是在全域執行上下文 (GEC) 內建立的。與 GEC 不同,一個程式中可以有多個 FEC。每個 FEC 都會經歷自己的創建和執行階段,並擁有自己的變數和詞法環境。詞法環境使函數能夠從其外部作用域存取變數。
當outerFunction被呼叫時,會建立一個新的FEC,在outerFunction內部,我們定義innerFunction,由於詞法作用域,它可以存取outerVariable。在outerFunction返回後,outerFunction的執行上下文將從呼叫堆疊中刪除,但innerFunction由於閉包而保留對outerVariable的存取。因此,當我們稍後呼叫closureExample()時,即使outerFunction已經完成,它仍然可以記錄outerVariable。
閉包的實際應用
讓我們來看看以下範例:
Let’s look at the example below: function outerFunction() { let outerVariable = 'I am John Doe'; return function innerFunction() { console.log(outerVariable); }; } const closureExample = outerFunction(); closureExample(); // Outputs: "I am John Doe"
你認為這段程式碼的輸出會是什麼?你們中的許多人可能猜到了 5,但這真的是正確的輸出嗎?事實上,不,原因如下。函數 y() 引用變數 a,而不是其初始值。當 z() 被呼叫時,由於返回內部函數之前進行了更新,它會記錄 a 的當前值,即 50。讓我們探討另一個例子:
function x(){ let a = 5 function y(){ console.log(a) } a = 50 return y; } let z = x(); console.log(z) z();
程式碼展示了閉包的威力。即使在最裡面的函數 z() 中,它仍然可以從其父作用域存取變數。如果我們檢查瀏覽器並檢查 Sources 選項卡,我們可以看到 x 和 y 上都形成了閉包,這允許 z() 從其父上下文存取 a 和 b。
使用閉包的優點
閉包在 JavaScript 中提供了多種優勢,特別是在編寫更靈活、模組化和可維護的程式碼時。以下是一些主要優點:
1。回呼函數: 閉包在處理非同步程式設計時非常強大,例如回呼、事件監聽器和 Promise。即使在外部函數完成後,它們也允許回調函數保持對外部函數變數的存取。
// GLOBAL SCOPE let myName = "John Doe"; function globalScope() { console.log(myName); } globalScope(); //Output John Doe console.log(myName); // Accessible here as well // LOCAL SCOPE function localScope() { let age = 30; console.log(age); } localScope(); //Output 30 console.log(age); //Output age is not defined (Not Accessible)
2。模組化和可維護性: 閉包允許開發人員編寫更小、可重複使用的程式碼區塊,從而鼓勵模組化。由於閉包可以在函數呼叫之間保留變量,因此減少了對重複邏輯的需求並提高了可維護性。
3。避免全域變數: 閉包有助於減少對全域變數的需求,從而避免潛在的命名衝突並保持全域命名空間乾淨。透過使用閉包,您可以將資料儲存在函數範圍內而不是全域。
結論
閉包是 JavaScript 中一個強大的概念,它允許函數記住和存取其外部作用域中的變量,甚至在函數執行之後也是如此,從而擴展了函數的功能。此功能在創建更模組化、靈活且高效的程式碼方面發揮著重要作用,特別是在處理非同步任務、回調和事件偵聽器時。雖然閉包一開始看起來很複雜,但掌握它們將使您能夠編寫更複雜和優化的 JavaScript。當您繼續練習時,您將發現閉包如何幫助編寫更乾淨、更易於維護的應用程式。不斷嘗試,很快閉包將成為你的 JavaScript 工具箱的自然組成部分。
以上是JavaScript 閉包的魔力:清晰易懂的指南的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

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

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

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

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

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。
