作用域的由來
編程語言的基本功能就是能夠存儲變量當(dāng)中的值,并且能夠?qū)ζ溥M(jìn)行訪問和修改,將變量引入程序會引起幾個有意思的問題?
1.變量儲存在哪里?
2.程序需要的時候如何找到他們?
//這些問題說明需要一套設(shè)計良好的規(guī)則來存儲變量,并且之后可以方便地找到這些變量,這套規(guī)則就是作用域!
//那么接著問題又來了,我們?nèi)绾卧O(shè)置這些作用域的規(guī)則呢?
編譯原理
- JavaScript是一門編譯語言,但是它又和傳統(tǒng)的編譯語言不同,它不是提前編譯的,編譯結(jié)果也不能在分布式系統(tǒng)中進(jìn)行移植,盡管如此JavaScript引起進(jìn)行編譯的步驟和傳統(tǒng)的編譯語言非常相似
編譯語言:在代碼執(zhí)行前有一個編譯過程,將代碼解釋成機械語言,以后再用這段代碼,就不用再翻譯了
解釋語言:在代碼運行的時候,邊翻譯邊執(zhí)行,明顯這種方式的代碼運行速度是比較慢的
- 傳統(tǒng)編譯語言,程序中的一段源代碼在執(zhí)行之前要經(jīng)歷三個步驟,統(tǒng)稱"編譯"
詞法分析,語法分析,代碼生成
- 任何JavaScript代碼在執(zhí)行之前都進(jìn)行編譯,var a =2 ;這句簡單的代碼,在運行前,瀏覽器中的JavaScript編譯器,會對它進(jìn)行編譯,然后執(zhí)行
//計算機是一個機器,機器只認(rèn)識0和1,任何高級的語言都需要編譯器來把代碼翻譯成機器語言,機器才能運行.
//互聯(lián)網(wǎng)技術(shù)就像一座大廈,大廈是一磚一瓦由低到高建立起來的 - 瀏覽器中主要有以下幾個角色
//JavaScript引擎,JavaScript編譯器,作用域,
//JavaScript引擎負(fù)責(zé)代碼的編譯和執(zhí)行工作
//JavaScript編譯器負(fù)責(zé)代碼的編譯工作
//作用域負(fù)責(zé)和兩者溝通的角色
var a =2 ;就以這句簡單的代碼為例
//遇到var a的時候,編譯器會詢問作用域是否已經(jīng)有一個該名稱的變量存在于同一個作用域的集合中?如果是,編譯器會忽略該聲明,繼續(xù)進(jìn)行編譯,否則它會要求作用域在當(dāng)前作用域的集合中聲明一個新的變量,并命名為a
//接下來編譯器會為引起生成運行時所需要的代碼,這些代碼被用來處理a=2這個賦值操作,引擎運行時首先詢問作用域,在當(dāng)前的作用域集合中是否存在一個叫做a的變量?如果是引擎就會使用這個變量,否則,引擎會繼續(xù)向上索引查找該變量
//如果引擎找到了a變量,就會將2賦值給它,否則引擎就會拋出異常
- 總結(jié):
變量的賦值操作會執(zhí)行兩個動作,首先編譯器會在作用域中聲明一個變量(如果之前沒有聲明過),然后在運行時引擎會在作用域中查找該變量,如果能夠找到就會對它賦值
編輯器有話說
- 編譯器在編譯過程的第二部中生成了代碼,引擎執(zhí)行時,會通過查找變量a來判斷它是否聲明過,查找的過程由作用域來協(xié)助,但是引擎執(zhí)行怎樣的查找,會影響最終的查找結(jié)果
- 當(dāng)變量出現(xiàn)在復(fù)制操作的左側(cè)時,進(jìn)行LHS查詢,出現(xiàn)在右側(cè)時進(jìn)行RHS查詢
//區(qū)別在于,RHS查找,與簡單的查找某個變量的值沒有區(qū)別,而LHS查找是試圖
找到變量的容器本身,從這個角度上來說,RHS并不是真的意義上的賦值操作的右側(cè),更準(zhǔn)確來說是非左側(cè)
//更準(zhǔn)確地說:賦值操作的目標(biāo)是誰(LHS)
誰是賦值操作的源頭(RHS)
作用域嵌套
- 作用域是根據(jù)名稱查找變量的一套規(guī)則
- 實際情況中,當(dāng)一塊或函數(shù)嵌套在另一塊或函數(shù)中時,就會發(fā)生作用域的嵌套,因此,在當(dāng)前作用域中無法找到某個變量時,引擎就會在外層嵌套的作用域中繼續(xù)查找,知道找到該變量或抵達(dá)最外層的作用域(全局作用域),如果還是沒有找到就停止