在JS中,引擎,編譯器,作用域分別扮演以下角色: 引擎:負責整個Js程式的編譯以及執行過程。 編譯器:負責語法分析以及代碼生成等。 作用域:負責收集並維護所有聲明的標示符(變數)組成的一系列查詢,並實施一套嚴格的規則,確定當前執行的代碼對這些標識符的訪問許可權。 下麵用一個小例子來表示: var a ...
在JS中,引擎,編譯器,作用域分別扮演以下角色:
引擎:負責整個Js程式的編譯以及執行過程。
編譯器:負責語法分析以及代碼生成等。
作用域:負責收集並維護所有聲明的標示符(變數)組成的一系列查詢,並實施一套嚴格的規則,確定當前執行的代碼對這些標識符的訪問許可權。
下麵用一個小例子來表示:
var a = 2;
1.首先,遇到var a,編譯器會詢問當前作用域是否有一個該變數存在,如果存在,編譯器則會忽略進行下一步,否則編譯器會要求作用域在當前聲明一個新的變數,並命名為a。
2.接下來編譯器會為引擎生成運行時所需要的代碼,這些代碼被用來處理 a = 2這個賦值操作,引擎運行時首先詢問作用域,是否存在變數a,若存在,引擎就會直接使用該變數,否則引擎會繼續向上一個作用域尋找,直到找到為止,如果在全局作用域還未找到,此時引擎會拋出一個異常。
關於引擎查詢:
引擎查詢有兩種查詢方式,分別為LHS(左查詢)和RHS(非左查詢)。
LHS查詢是找到該變數的容器,如var a = 2; 在查詢a時就需用到LHS查詢。
RHS查詢可以理解為找到該變數的值,如 a = b ,在查詢b時,僅需要得到它的值,並不關心他本身容器,故使用RHS查詢。
一個小例子便於理解:
function foo(a){
var a = b;
return a+b;
}
var c = foo(2);
其中使用了三次LHS,分別為 var c,var a,以及foo(2)的時候把2賦值給a(隱式賦值);
使用了四次RHS,分別為foo(2), = b, return a + b(a,b)各一次。
關於為什麼要區分LHS和RHS是很重要呢?
因為異常。
在變數還未聲明的情況下(即在任何作用域都找不到該變數),這兩種查詢的方式是不同的。
LHS:
LHS在非嚴格模式下,找不到該變數時,它會直接聲明一個該變數,如a = b,中的a會被聲明。但如果在嚴格模式下,則會拋出一個ReferenceError.
RHS:
RHS找不到時會直接拋出一個ReferenceError.
ReferenceError是同作用域判定失敗有關,而TypeError則是代表作用域判別成功,但是對結果的操作屬於非法,比如試圖對一個非函數的值進行函數調用。