一偎蘸、引擎,編譯器杰妓,作用域
- 引擎: ??負(fù)責(zé)整個Javascript程序的編譯及執(zhí)行過程。
- 編譯器:負(fù)責(zé)語法分析及代碼生成碘勉。
- 作用域:負(fù)責(zé)收集并維護(hù)有所有聲明的標(biāo)識符組成的一系列查詢巷挥。
二、編譯器(編譯過程var a=1;)
- 第一步:編譯器首先會將這段代碼分解成詞法單元验靡,然后將詞法單元解析成樹結(jié)構(gòu)倍宾。
- 第二步:對詞法單元進(jìn)行解析,解析到var a時胜嗓,編譯器會詢問作用域是否存在一個變量名為a在同一作用域的集合中高职。如果有,編譯器就忽略此聲明辞州。反之怔锌,在要求的作用域下聲明變量。
- 第三步:生成可以運行代碼(=1)給引擎執(zhí)行变过,生成代碼的這個過程就涉及到LHS和RHS(具體細(xì)節(jié)看第三節(jié))的倆種賦值概念埃元。
- 第四步:引擎運行編譯器生成的代碼時,會詢問作用域是否存在在當(dāng)前作用域下變量名為a的集合媚狰,如果沒有岛杀,則在向上一級作用域查找變量名a(具體細(xì)節(jié)看第四節(jié))。如果有哈雏,引擎則對變量名為a的集合賦值楞件。
三、LHS和RHS
?????? 3.1 什么是LHS裳瘪、RHS
????????????LHS:賦值操作的目標(biāo)是誰土浸。
????????????RHS:誰是賦值操作的源頭。
上面的解釋是我通過其他途徑了解到的彭羹,我自己也不是很明白黄伊。按我自己的理解:LHS就是正常的變量賦值(a=1),RHS就是通過第三方來賦值的(a=b派殷,b=2)还最。
舉例:
function foo(a){
console.log(a);
}
var b=2
foo(b);
程序調(diào)用foo() 方法:
- 步驟一:因為函數(shù)需要傳參,故先對foo()進(jìn)行RHS賦值
- 步驟二:對形參a進(jìn)行LHS賦值(a=2)
- 步驟三:對console進(jìn)行RHS賦值
- 步驟四:對參數(shù)a進(jìn)行LHS賦值(a=2)
- 注意:每次程序執(zhí)行(引擎)訪問變量或函數(shù)時毡惜,都會去詢問作用域該變量或函數(shù)是否存在拓轻。如果不存在則可能會向上查找,或者拋異常(第五小節(jié))经伙。
?????? 3.2 區(qū)分LHS扶叉、RHS的重要性
????????????(1)如果是LHS賦值,在頂級作用域(全局)找不到改變量,則全局作用域下枣氧,會隱式創(chuàng)建一個具有該名稱的變量溢十,并將其返還給引擎(非嚴(yán)格模式下)
function foo(){
a=2;
}
//a為定義,此時全局創(chuàng)建一個名為a的變量集合
????????????(2)如果是RHS賦值达吞,在所有嵌套的作用域下遍尋不到該所需的變量张弛,則拋出異常ReferenceError
function foo(){
var a=b;
}
//a為定義,此時會拋ReferenceError
但在ES5中對于這個弊端酪劫,也給出了規(guī)定吞鸭。(具體看第五小節(jié))
四、引擎尋找變量
- 當(dāng)引擎在當(dāng)前作用域找不到變量名為a的集合時契耿,會向外層嵌套的作用域進(jìn)行查找瞒大,直到找到該變量為止,或抵達(dá)最外層的作用域(也就是全局作用域)為止搪桂。
- 在ES6中透敌,對這個弊端,也得到了解決踢械。具體可以點擊這里
五酗电、異常
- 在ES5中引入了“嚴(yán)格模式”,嚴(yán)格禁止自動或隱式地創(chuàng)建全局變量内列。
- 在嚴(yán)格模式中LHS查詢失敗時撵术,并不會創(chuàng)建并返回一個全局變量,引擎會拋出同查詢失敗時類似的ReferenceError異常话瞧。
- 對于RHS賦值嫩与,如果查詢找到一個變量,但是如果你嘗試對這個變量進(jìn)行不合理操作交排,比如對一個非函數(shù)類型的值進(jìn)行函數(shù)調(diào)用划滋,或者引用null,underfined類型的值中的操作,那么引擎會拋出另外一個異常埃篓,叫做TypeError处坪。
- 總結(jié):在嚴(yán)格模式下,拋出異常ReferenceError則同作用域判別失敗相關(guān)架专,而TypeError則代表作用域判別成功了同窘,但是對結(jié)果的操作是不合法的。