JavaScript執行機制範例程式碼分析
#從一個簡單的問題談起:
<script type="text/javascript"> alert(i); var i = 1; </script>
輸出結果是undefined, 這種現像被稱為「預解析」:JavaScript引擎會優先解析var變數和function定義。在預解析完成後,才會執行程式碼。如果一個文件流程包含多個script程式碼段(用script標籤分隔的js程式碼或引入的js檔案).
運行順序是:
step1. 讀入第一個程式碼段
step2. 做語法分析,有錯誤則報語法錯誤(例如括號不符等),並跳到step5
step3. 對var變數和function定義做「預解析」(永遠不會報錯的,因為只解析正確的宣告)
step4. 執行程式碼段,有錯則報錯(例如變數未定義)
step5. 如果還有下一個程式碼段,則讀入下一個程式碼段,重複step2
step6. 結束
上面的分析,已經能解釋很多問題了,但老覺得欠缺點什麼。例如step3裡,「預解析」究竟是怎麼回事?還有step4裡,看下面的例子:
<script type="text/javascript"> alert(i); // error: i is not defined. i = 1; </script>
為什麼第一句會導致錯誤? JavaScript中,變數不是可以不定義嗎?
編譯過程
時間如白馬過隙,書櫃旁翻開恍如隔世般的《編譯原理》,熟悉而又陌生的空白處有著這樣的筆記:
對於傳統編譯型語言來說,編譯步驟分為:詞法分析、語法分析、語意檢查、程式碼最佳化和位元組生成。
但對於解釋型語言來說,透過詞法分析和語法分析得到語法樹後,就可以開始解釋執行了。
簡單地說,詞法分析是將字元流(char stream)轉換為記號流(token stream), 例如將c = a – b;轉換為:
NAME "c" EQUALS NAME "a" MINUS NAME "b" SEMICOLON
上面只是範例,更進一步的了解請查看Lexical Analysis.
《JavaScript權威指南》的第2章,講的就是詞法結構(Lexical Structure),ECMA-262 中也有描述。詞法結構是一門語言的基礎,很容易掌握。至於詞法分析的實現那是另一個研究領域,在此不探究。
可以拿自然語言來類比,詞法分析是一對一的硬性翻譯,例如一段英文,逐詞翻譯成中文,得到的是一堆記號流,還很難理解。進一步的翻譯,就需要語法分析了,下圖是一個條件語句的語法樹:
構造語法樹的時候,如果發現無法構造,比如if(a { i = 2; }, 就會報語法錯誤,並結束整個程式碼區塊的解析,這就是本文開頭部分的step2.
透過語法分析,建構出語法樹後,翻譯出來的句子可能還會有模糊的地方,接下來還需要進一步的語意檢查。精力有限,沒時間去看JS的引擎實現,不敢確定JS引擎中是否有語意檢查這一步)。和語法分析,之後可能還有語意檢查、程式碼最佳化等步驟,等這些編譯步驟完成之後(任何語言都有編譯過程,只是解釋型語言沒有編譯成二進位程式碼),才會開始執行程式碼。
上面的編譯過程,還是無法更深入的解釋文章開頭部分的“預解析”,我們還得仔細探究下JavaScript程式碼的執行過程。愛民在《JavaScript語言精髓與程式設計實踐》的第二部分,對此有非常仔細的分析。 以下是我的一些領悟:透過編譯,JavaScript程式碼已經翻譯成了語法樹,然後會立刻依照語法樹執行。時決定而不是執行時決定,也就是說詞法作用域取決於源碼,編譯器透過靜態分析就能確定,因此詞法作用域也叫做靜態作用域(static scope)。無法僅透過靜態技術實現,實際上,只能說JS的作用域機制非常接近lexical scope.JS引擎在執行每個函數實例時,都會建立一個執行環境(execution context)。 context中包含一個呼叫物件(call object), 呼叫物件是一個scriptObject結構,用來保存內部變數表varDecls、內嵌函數表funDecls、父級引用列表upvalue等語法分析結構(注意:varDecls和funDecls等資訊是在語法分析階段就已經得到,並保存在語法樹中。函數實例執行時,會將這些資訊從語法樹複製到 scriptObject上)。 scriptObject是與函數相關的一套靜態系統,與函數實例的生命週期一致。lexical scope是JS的作用域机制,还需要理解它的实现方法,这就是作用域链(scope chain)。scope chain是一个name lookup机制,首先在当前执行环境的scriptObject中寻找,没找到,则顺着upvalue到父级scriptObject中寻找,一直 lookup到全局调用对象(global object)。
当一个函数实例执行时,会创建或关联到一个闭包(closure)。 scriptObject用来静态保存与函数相关的变量表,closure则在执行期动态保存这些变量表及其运行值。closure的生命周期有可能比函数实例长。函数实例在活动引用为空后会自动销毁,closure则要等要数据引用为空后,由JS引擎回收(有些情况下不会自动回收,就导致了内存泄漏)。
别被上面的一堆名词吓住,一旦理解了执行环境、调用对象、闭包、词法作用域、作用域链这些概念,JS语言的很多现象都能迎刃而解。
小结
至此,对于文章开头部分的疑问,可以解释得很清楚了:
step3中所谓的“预解析”,其实是在step2的语法分析阶段完成,并存储在语法树中。当执行到函数实例时,会将varDelcs和funcDecls从语法树中复制到执行环境的scriptObject上。
step4中,未定义变量意味着在scriptObject的变量表中找不到,JS引擎会沿着scriptObject的upvalue往上寻找,如果都没找到,对于写操作i = 1; 最后就会等价为 window.i = 1; 给window对象新增了一个属性。对于读操作,如果一直追溯到全局执行环境的scriptObject上都找不到,就会产生运行期错误。
理解后,雾散花开,天空一片晴朗。
最后,留个问题给大家:
<script type="text/javascript"> var arg = 1; function foo(arg) { alert(arg); var arg = 2; } foo(3); </script>
请问alert的输出是什么?
以上是JavaScript運行機制範例程式碼分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

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

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

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

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

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

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

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

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


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

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

熱門文章

熱工具

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

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

Atom編輯器mac版下載
最受歡迎的的開源編輯器

Dreamweaver Mac版
視覺化網頁開發工具

SublimeText3 Linux新版
SublimeText3 Linux最新版