JavaScript的運行機制

編譯 (解析)

對于傳統編譯型語言(例如:Java)來說,編譯步驟分為:詞法分析->語法分析->語義檢查->代碼優化和字節生成。

對于解釋型語言(例如:JavaScript)來說,通過詞法分析和語法分析得到語法樹后,就可以開始解釋執行了。

詞法分析是將字符流(char stream)轉換為記號流(token stream),例如:

正常代碼

var result = testNum1 - testNum2;         

詞法分析后:

NAME "result"         
EQUALS        
NAME "testNum1"       
MINUS         
NAME "testNum2"       
SEMICOLON

可以拿自然語言來類比,詞法分析是一對一的硬性翻譯,比如一段英文,逐詞翻譯成中文,得到的是一堆記號流,還很難理解。進一步的翻譯,就需要語法分析了。生成語法樹例子:

正常代碼

if(typeof a == "undefined" ){  
  a = 0;  
}else{  
  a = a;  
}  
alert(a);

語法樹


執行

經過編譯階段的準備,JavaScript代碼在內存中已經被構建為語法樹,然后JavaScript引擎就會根據這個語法樹結構邊解釋邊執行了。

在解釋過程中,JavaScript引擎是嚴格按著作用域機制(scope)來執行的。JavaScript語法采用的是詞法作用域 (lexcical scope),也就是說JavaScript的變量和函數作用域是在定義時決定的,而不是執行時決定的,由于詞法作用域取決于源代碼結構,所以JavaScript解釋器只需要通過靜態分析就能確定每個變量、函數的作用域,這種作用域也稱為靜態作用域(static scope)。但需要注意,with和eval的語義無法僅通過靜態技術實現,實際上,只能說JS的作用域機制非常接近lexical scope。

JavaScript引擎在調用執行每個函數時,都會創建一個執行環境(execution context)。執行環境中包含一個調用對象(call object), 調用對象是一個scriptObject結構,用來保存內部變量表varDecls、內嵌函數表funDecls、父級引用列表upvalue等語法分析結構(注意:varDecls和funDecls等信息是在語法分析階段就已經得到,并保存在語法樹中。函數調用執行時,會將這些信息從語法樹復制到 scriptObject上)。scriptObject是與函數相關的一套靜態系統,與函數實例的生命周期保持一致。

JavaScript引擎通過作用域鏈(scope chain)把多個嵌套的作用域串連在一起,并借助這個鏈條幫助JavaScript解釋器檢索變量的值。這個作用域鏈相當于一個索引表,并通過編號來存儲它們的嵌套關系。當JavaScript解釋器檢索變量的值,會按著這個索引編號進行快速查找,直到找到全局對象(global object)為止,如果沒有找到值,則傳遞一個特殊的undefined值。

如果函數引用了外部變量的值,則JavaScript引擎會為該函數創建一個閉包體(closure),閉包體是一個完全封閉和獨立的作用域,它不會在函數調用完畢后就被JavaScript引擎當做垃圾進行回收。閉包體可以長期存在,因此開發人員常把閉包體當做內存中的蓄水池,專門用來長期保存變 量的值。

只有當閉包體的外部引用被全部設置為null值時,該閉包才會被回收。當然,也容易引發垃圾泛濫,甚至出現內存外溢的現象。


編譯和執行的關系

例子:

alert(a);  // 返回值undefined  
var a =1;  
alert(a);  // 返回值1  

為什么這段代碼執行不會報錯?

因為:JavaScript引擎解析腳本時,它會在預編譯期對所有聲明的變量和函數進行處理。

分析:由于變量聲明是在預編譯期被處理的,所以在執行期間對于所有代碼來說,都是可見的。但是,你也會看到,執行上面代碼,提示的值是 undefined,而不是1。這是因為,變量初始化過程發生在執行期,而不是預編譯期。在執行期,JavaScript解釋器是按著代碼先后順序來解釋執行的,如果在前面代碼行中沒有為變量賦值,則JavaScript解釋器會使用默認值undefined。由于在第二行中為變量a賦值了,所以在第三行代 碼中會提示變量a的值為1,而不是undefined。

//代碼1  
testFun();  // 調用函數,返回值1  
function testFun(){  
    alert(1);  
}   

//代碼2  
testFun();   // 調用函數,返回語法錯誤  
var testFun = function(){  
    alert(1);  
}  

分析:

代碼1,在函數聲明前調用函數也是合法的,并能夠被正確解析。

代碼2,定義的函數僅作為值賦值給變量testFun,所以在預編譯期,JavaScript解釋器只能夠為聲明變量f進行處理,而對于變量testFun的值,只能等到執行期時按順序進行賦值,自然就會出現語法錯誤,提示找不到對象testFun。

原文:JavaScript的運行機制

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,401評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,011評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,263評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,543評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,323評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,874評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,968評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,095評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,605評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,551評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,720評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,242評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,961評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,358評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,612評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,330評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,690評論 2 370

推薦閱讀更多精彩內容