JavaScript 詞法作用域不完全指北
在 JavaScript 作用域不完全指北 中,我們介紹了作用域的概念以及 JavaScript 引擎、編譯器和作用域的關係。作用域有兩種主要的工作模型:詞法作用域和動態作用域。其中最為普遍的也是大多數程式語言所採用的是詞法作用域,我們主要對其進行研究學習。
在傳統編譯語言的流程中, 程式中的一段原始碼在執行之前會經歷三個步驟, 統稱為“編譯”。
- 分詞/詞法分析(Tokenizing/Lexing)
這個過程會將由字元組成的字串分解成(對程式語言來說) 有意義的程式碼塊, 這些程式碼塊被稱為詞法單元。
- 解析/語法分析(Parsing)
這個過程是將詞法單元流(陣列) 轉換成一個由元素逐級巢狀所組成的代表了程式語法結構的樹。 這個樹被稱 為“抽象語法樹”(Abstract Syntax Tree, AST)。
- 程式碼生成
將“抽象語法樹” 轉換為可執行程式碼的過程稱被稱為程式碼生成。 這個過程與語言、 目標平臺等息息相關。
第一個步驟也叫作詞法化,詞法作用域就是定義在詞法階段的作用域。簡單地說,詞法作用域是由你寫程式碼時將變數和塊作用域寫在哪裡來決定的,詞法分析器處理程式碼時會保持作用域不變。
我們通過以下程式碼來分析一下詞法作用域:
function foo(a){
var b = a * 2;
function bar(c){
console.log(a,b,c);
}
bar(b * 3);
}
foo(2); //2 4 12
在例項程式碼中,會有三個逐級巢狀的作用域。
1.包含著全域性作用域,其中有一個識別符號 foo
2.包含著 foo 所建立的作用域,其中有三個識別符號:a,bar,b
3.包含著 bar 所建立的作用域,其中有一個識別符號:c
引擎使用作用域的結構和相互之間的位置關係來查詢識別符號。我們在上篇文章中講過,引擎在作用域中進行變數查詢的過程,是從當前作用域逐級向外,直到遇到第一個匹配的識別符號結束。
在例項程式碼中,引擎執行 console.log(a,b,c);
宣告,並查詢變數 a , b , c 的引用。首先從最內部的作用域,也就是 bar 函式的作用域開始查詢,引擎無法在這裡查詢到變數 a ,便會到上一級所巢狀的 foo 函式作用域中進行查詢。引擎在這裡找到了變數 a 的引用,便會停止對變數 a 引用的查詢。對 b 來說也是一樣的。對 c 來說,引擎在 bar 函式作用域中就會找到它。
詞法作用域意味著作用域是由書寫程式碼時函式的位置來決定的。編譯的詞法分析階段基本能夠知道全部識別符號在哪裡以及是如何宣告的,從而預測在引擎執行程式碼過程中如何對它們進行查詢。
參考
- 《你不知道的JavaScript》
- 《深入理解JavaScript特性》
作者:CoderFocus
微信公眾號:
宣告:本文為博主學習感悟總結,水平有限,如果不當,歡迎指正。如果您認為還不錯,不妨點選一下下方的【推薦】按鈕,謝謝支援。轉載與引用請註明作者及出處。