變量住在哪里?換句話說,它們儲(chǔ)存在哪里?最重要的是,程序需要時(shí)如何找到它們?
這些問題說明需要一套設(shè)計(jì)良好的規(guī)則來存儲(chǔ)變量,并且之后可以方便地找到這些變量。
這套規(guī)則被稱為作用域。
在傳統(tǒng)編譯語言的流程中,程序中的一段源代碼在執(zhí)行之前會(huì)經(jīng)歷三個(gè)步驟,統(tǒng)稱為“編譯”。
- 分詞/詞法分析(Tokenizing/Lexing)
這個(gè)過程會(huì)將由字符組成的字符串分解成(對(duì)編程語言來說)有意義的代碼塊,這些代
碼塊被稱為詞法單元(token)。例如,考慮程序 var a = 2; 。這段程序通常會(huì)被分解成
為下面這些詞法單元: var 、 a 、 = 、 2、; ??崭袷欠駮?huì)被當(dāng)作詞法單元,取決于空格在這門語言中是否具有意義。
- 解析/語法分析(Parsing)
這個(gè)過程是將詞法單元流(數(shù)組)轉(zhuǎn)換成一個(gè)由元素逐級(jí)嵌套所組成的代表了程序語法
結(jié)構(gòu)的樹。這個(gè)樹被稱為“抽象語法樹”(Abstract Syntax Tree,AST)。
var a = 2; 的抽象語法樹中可能會(huì)有一個(gè)叫作 VariableDeclaration 的頂級(jí)節(jié)點(diǎn),接下
來是一個(gè)叫作 Identifier (它的值是 a )的子節(jié)點(diǎn),以及一個(gè)叫作 AssignmentExpression 的子節(jié)點(diǎn)。 AssignmentExpression 節(jié)點(diǎn)有一個(gè)叫作 NumericLiteral (它的值是 2 )的子節(jié)點(diǎn)。
- 代碼生成
將 AST 轉(zhuǎn)換為可執(zhí)行代碼的過程稱被稱為代碼生成。這個(gè)過程與語言、目標(biāo)平臺(tái)等息
息相關(guān)。拋開具體細(xì)節(jié),簡單來說就是有某種方法可以將 var a = 2; 的 AST 轉(zhuǎn)化為一組機(jī)器指令,用來創(chuàng)建一個(gè)叫作 a 的變量(包括分配內(nèi)存等),并將一個(gè)值儲(chǔ)存在 a 中。
對(duì)于 JavaScript 來說,大部分情況下編譯發(fā)生在代碼執(zhí)行前的幾微秒(甚至更短?。┑臅r(shí)間內(nèi)。簡單地說,任何 JavaScript 代碼片段在執(zhí)行前都要進(jìn)行編譯(通常就在執(zhí)行前)。因此,JavaScript 編譯器首先會(huì)對(duì) var a = 2; 這段程序進(jìn)行編譯,然后做好執(zhí)行它的準(zhǔn)備,并且通常馬上就會(huì)執(zhí)行它。