簡(jiǎn)析JavaScript中的編譯原理和提升

JS編譯原理

JavaScript是一門可歸類于"動(dòng)態(tài)""解釋執(zhí)行"的編程語(yǔ)言掖举,與傳統(tǒng)的編程語(yǔ)言不同,它不是提前編譯的,編譯結(jié)果也不能在分布式系統(tǒng)中移植仪芒。通常一段源代碼在執(zhí)行之前會(huì)經(jīng)歷三個(gè)過(guò)程:

分詞/詞法分析

這個(gè)過(guò)程會(huì)將字符串分割為有意義的代碼塊,這些代碼塊稱之為詞法單元耕陷。例如變量的聲明:
var a = 2;
這行代碼會(huì)被分為以下詞法單元:var掂名、a、=哟沫、2(空格算不算詞法單元取決于空格對(duì)于該編程語(yǔ)言是否具有意義)饺蔑;這些零散的詞法單元會(huì)組成一個(gè)詞法單元流(數(shù)組)進(jìn)行解析。

解析/與法分析

這個(gè)過(guò)程會(huì)將詞法單元流轉(zhuǎn)換成一棵抽象語(yǔ)法樹(Abstract Syntax Tree嗜诀,AST)在線解析工具猾警。
var a = 2;的詞法單元流就會(huì)被解析為下面的AST:

062AF4C4-FE8A-43BC-8D0B-A0B6C0B145F3.png

代碼生成

將AST轉(zhuǎn)化為可執(zhí)行的代碼孔祸。

整個(gè)過(guò)程看似很簡(jiǎn)單,但是在語(yǔ)法分析和代碼生成階段有很多坑等著踩肿嘲。
這里又要引入幾個(gè)概念了

成員:

1.引擎:負(fù)責(zé)整個(gè)過(guò)程中javascript的編譯及執(zhí)行過(guò)程融击。瀏覽器不同,其引擎也不同雳窟,比如Chrome采用的是v8尊浪,Safari采用的是SquirrelFish Extreme。
2.編譯器:負(fù)責(zé)語(yǔ)法分析和代碼生成封救。
3.作用域:負(fù)責(zé)收集并維護(hù)所有的標(biāo)識(shí)符(變量)簡(jiǎn)析JavaScript中的作用域與作用域鏈

例子分析:

還是對(duì)最簡(jiǎn)單的例子進(jìn)行分析拇涤,var a = 2;,首先進(jìn)行詞法分析誉结,然后將詞法單元流交給編譯器生成AST鹅士,再有編譯器生成可執(zhí)行的代碼。
???A.編譯器遇到var a;會(huì)詢問(wèn)同一作用域集是否有存在同名的變量惩坑,如果有掉盅,就忽略該聲明,繼續(xù)編譯以舒;如果沒(méi)有編譯器就會(huì)要求作用域在當(dāng)前作用域的集合生命一個(gè)新的變量趾痘,并命名為a。
???B.編譯器會(huì)為引擎的運(yùn)行生成一些列代碼蔓钟,這些代碼用于為變量a進(jìn)行賦值操作永票。引擎會(huì)詢問(wèn)當(dāng)前作用域是否有這個(gè)變量的存在,如果有則進(jìn)行賦值操作滥沫,如果沒(méi)有就開始查找這個(gè)變量(從當(dāng)前作用域向上查找侣集,直到全局作用域,如果還是沒(méi)有兰绣,就會(huì)拋出一個(gè)異常)世分。
???C.LHS和RHS,當(dāng)引擎執(zhí)行編譯器給的代碼(賦值操作)時(shí),會(huì)通過(guò)查找這個(gè)變量來(lái)判斷這個(gè)變量是否已經(jīng)聲明,這個(gè)過(guò)程需要作用域的協(xié)助缀辩,而查找的方式分為兩種:LHS(“賦值操作的目標(biāo)是誰(shuí)”)臭埋、RHS(”誰(shuí)是賦值操作的源頭“)。例如下面這個(gè)例子:

 var a;  //RHS引用
 a = 2;  //LHS引用
 alert(a);  //RHS引用
/*這段代碼塊既有RHS引用也有LHS引用雌澄,
foo(2),2被當(dāng)作函數(shù)參數(shù)傳遞給foo()時(shí)杯瞻,2會(huì)被分配給變量a(a = 2);
*/
  function foo(a){
  alert(a);
}
  foo(2);

區(qū)分RHS和LHS也很重要镐牺,尤其分析異常時(shí)。例如下面這個(gè)例子:

function foo(a){
  alert(a + b); 
  b = a;
}
foo(2);

第一次對(duì)b進(jìn)行RHS查詢會(huì)查詢不到這個(gè)變量魁莉,因?yàn)樗且粋€(gè)未聲明的變量睬涧,在所有作用域都無(wú)法找到(var b;);此時(shí)引擎會(huì)拋出一個(gè)異常(ReferenceError)募胃。在非嚴(yán)格模式下,當(dāng)引擎進(jìn)行LHS查詢查詢不到某個(gè)變量時(shí)畦浓,全局作用域會(huì)創(chuàng)建一個(gè)同名的變量交給引擎痹束,當(dāng)然這個(gè)變量具有全局作用域;而在嚴(yán)格模式下,引擎會(huì)拋出ReferenceError的異常讶请。

提升

變量和函數(shù)在內(nèi)的聲明都在任何代碼執(zhí)行前被處理祷嘶。聲明操作在編譯階段時(shí)進(jìn)行的,而賦值操作是在等到執(zhí)行階段才執(zhí)行夺溢。

//代碼塊1
  var a = 2;
  alert(a);  //  輸出2
//代碼塊2 
  b = 2;
  var b;
  alert(b);  //輸出2
//代碼塊3
  alert(c);  //輸出undefined
  var c = 2;
//代碼塊4
  var d;
  alert(d); //輸出undefined
  d = 2;

代碼塊2论巍,4等價(jià)于代碼塊1,3(除了變量名不同风响,內(nèi)存地址不同)嘉汰;這個(gè)過(guò)程就好像變量和函數(shù)聲明的代碼被移動(dòng)到了最上面,這個(gè)過(guò)程就叫提升状勤。

函數(shù)聲明可以提升鞋怀,函數(shù)表達(dá)式不能提升。
//函數(shù)聲明可以提升
foo();  //輸出2持搜;
function foo(){
  alert(2); 

//函數(shù)表達(dá)式不可提升
bar();  //TypeError
var bar = function f1(){
  alert(2);
}
函數(shù)聲明優(yōu)先于變量聲明提升,出現(xiàn)在后面的函數(shù)聲明可以覆蓋之前的聲明密似。
foo();  //輸出3
function foo(){
  alert(1);
}
var foo = function bar(){
  alert(2);
}
function foo(){
  alert(3);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市朵诫,隨后出現(xiàn)的幾起案子辛友,更是在濱河造成了極大的恐慌,老刑警劉巖剪返,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件废累,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡脱盲,警方通過(guò)查閱死者的電腦和手機(jī)邑滨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)钱反,“玉大人掖看,你說(shuō)我怎么就攤上這事∶娓纾” “怎么了哎壳?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)尚卫。 經(jīng)常有香客問(wèn)我归榕,道長(zhǎng),這世上最難降的妖魔是什么吱涉? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任刹泄,我火速辦了婚禮外里,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘特石。我一直安慰自己盅蝗,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布姆蘸。 她就那樣靜靜地躺著墩莫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乞旦。 梳的紋絲不亂的頭發(fā)上贼穆,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音兰粉,去河邊找鬼故痊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛玖姑,可吹牛的內(nèi)容都是我干的愕秫。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼焰络,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼戴甩!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起闪彼,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤甜孤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后畏腕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缴川,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年描馅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了把夸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡铭污,死狀恐怖恋日,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嘹狞,我是刑警寧澤岂膳,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站磅网,受9級(jí)特大地震影響谈截,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一傻盟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嫂丙,春花似錦娘赴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至隅肥,卻和暖如春竿奏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背腥放。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工泛啸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人秃症。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓候址,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親种柑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子岗仑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持荠雕,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠驶赏,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 3,220評(píng)論 5 34
  • You don't KnowJS 引語(yǔ):你不懂的JS這本書?github上已經(jīng)有了7w的star最近也是張野大大給...
    Sleet閱讀 574評(píng)論 0 0
  • 在學(xué)習(xí) javascript 的過(guò)程中炸卑,我們第一步最應(yīng)該了解和掌握的就是作用域,與之相關(guān)還有程序是怎么編譯的母市,變量...
    liuxuan閱讀 1,171評(píng)論 1 8
  • 《你不知道的JavaScript》真的是一本好書矾兜,閱讀這本書,我有多次“哦患久,原來(lái)是這樣”的感覺(jué)椅寺,以前自以為理解了(...
    然并阮閱讀 619評(píng)論 2 9
  • 程序需要存儲(chǔ)變量中的值,并且能在之后對(duì)這個(gè)值進(jìn)行訪問(wèn)或修改蒋失。這些變量存儲(chǔ)在哪里返帕?程序如何找到他們?這些問(wèn)題需要一套...
    zyanfly閱讀 263評(píng)論 0 1