又是一年臨近年末了,年末制定下了許多計劃,正在一點一點實現,最近在開始讀《你不知道的Javascript》了,也會慢慢把讀書筆記經過博客的形式輸出出來,讓本身印象更深入,今天就來聊聊JS中的var a = 2;
這行代碼發生了什麼?編程
對於編程語言來講都會有一個編譯的過程,一段代碼在執行前大多都會經歷下面幾個步驟:(具體的細節會根據語言特性而異)數組
這個過程會將由字符組成的字符串分解成(對編程語言來講)有意義的代碼塊,這些代 碼塊被稱爲詞法單元(token)。例如,考慮程序 var a = 2;。這段程序一般會被分解成 爲下面這些詞法單元:var、a、=、2 、;。bash
這個過程是將詞法單元流(數組)轉換成一個由元素逐級嵌套所組成的表明了程序語法 結構的樹。這個樹被稱爲「抽象語法樹」(Abstract Syntax Tree,AST)。編程語言
將 AST 轉換爲可執行代碼的過程稱被稱爲代碼生成。這個過程與語言、目標平臺等息 息相關。 拋開具體細節,簡單來講就是有某種方法能夠將 var a = 2; 的 AST 轉化爲一組機器指 令,用來建立一個叫做 a 的變量(包括分配內存等),並將一個值儲存在 a 中。函數
從頭至尾負責整個 JavaScript 程序的編譯及執行過程。ui
負責語法分析及代碼生成等spa
負責收集並維護由全部聲明的標識符(變量)組成的一系列查詢,並實施一套很是嚴格的規則,肯定當前執行的代碼對這些標識符的訪問權限。code
咱們在瞭解了這些編譯中的基本概念後,咱們在來仔細看看var a = 2;
這行代碼發生了什麼;token
var a
,編譯器會詢問做用域是否已經有一個該名稱的變量存在於同一個做用域的集合中。若是是,編譯器會忽略該聲明,繼續進行編譯;不然它會要求做用域在當前做用域的集合中聲明一個新的變量,並命名爲 a。(變量聲明階段)總結:變量的賦值操做會執行兩個動做,首先編譯器會在當前做用域中聲明一個變量(若是以前沒有聲明過),而後在運行時引擎會在做用域中查找該變量,若是可以找到就會對它賦值。ip
咱們知道了var a = 2;js的執行過程了,那麼若是是var a = b;呢? 那麼這個過程對於b來講咱們如何查到變量b的值呢;
編譯器查找變量有兩種類型,一直是LHS,一種是RHS,舉個例子:
a = 2
複製代碼
這個例子就是LHS查詢,當編譯器去查找a變量的時候,實際上是爲了找到a變量的容器,去給a賦值,因此LHS查詢實際上是查詢變量的容器
console.log(a)
複製代碼
這個例子中的其實就是RHS查詢,當編譯器去查找a變量的時候,其實目的是找到a變量的值而不是他的容器,所以RHS查詢實際上是查詢變量的值
ok,咱們知道了以後咱們來嘗試一下一個進階例子。
function foo(a) { // 隱式的進行參數賦值 將a = 2; 進行LHS查詢 查詢到a容器 並進行賦值
var b = a; // RHS進行查詢 查詢到a變量的值 而後 LHS查詢 查詢到b容器並進行賦值
return a + b;// RHS進行查詢 查詢到a和b變量的值
}
var c = foo( 2 ); // 編譯器先RHS查找foo變量 而後進入到foo函數體 函數執行完成後,RHS查詢查詢變量c的容器並進行賦值
複製代碼
注:若是RHS查到了一個變量,可是這個變量的類型和咱們將要進行的操做不一樣時,好比試圖對一個非函數類型的值進行函數調用,那麼就會拋出TypeError的錯誤