理解JavaScript的預(yù)編譯

不要因?yàn)檎嫦嗪茈y理解就不告訴我真相是什么
這篇文章格式不好,請(qǐng)看我整理格式后的: http://www.reibang.com/p/b5a7bb95d8e0

也不知道最開始是在哪個(gè)老師還是哪本書或者是哪個(gè)同學(xué)那里聽來的秀又,或者說學(xué)來的說js是一門不需要編譯的語言,由瀏覽器直接解釋執(zhí)行。嗯很好理解嘛,當(dāng)時(shí)覺得也很對(duì)斧拍,寫完一個(gè)js文件引入到html中直接扔瀏覽器里面跑就OK了,并沒有像Java那樣要做一個(gè)javac hello.java 得到一個(gè)hello.class的編譯步驟杖小。但是當(dāng)我學(xué)到es6的時(shí)候就徹底懵逼了肆汹,es6中的的模塊章節(jié)中通篇都在講述import 和 expert這兩個(gè)風(fēng)騷到飛起的指令的各種花樣解鎖姿勢(shì),各種引用予权,其中很重要很基本的一個(gè)概念就是它跟node中require的區(qū)別昂勉?區(qū)別是什么呢,就是es6中的import是編譯時(shí)加載的扫腺,而node中的require是運(yùn)行時(shí)加載的岗照。還有另一個(gè)說法就是,es6中的import是靜態(tài)編譯階段執(zhí)行的笆环,所以在你import的代碼中不可以寫任何的一絲一毫的js邏輯判斷或者運(yùn)算的代碼攒至。比如阮老師告訴我們 import { 'f' + 'oo' } from 'my_module'; 這樣寫會(huì)報(bào)錯(cuò),原因是import 是靜態(tài)執(zhí)行的而 大括號(hào)中的加法代碼是運(yùn)行時(shí)的操作咧织,所以報(bào)錯(cuò)了嗓袱。
大神們對(duì)于自己理解的知識(shí)說起來總是一筆帶過,從不關(guān)心屌絲們對(duì)于一個(gè)概念為什么是這樣的可能都不懂习绢。
自己就曾在這里鉆過很長時(shí)間的牛角尖渠抹,偏執(zhí)于大家信口拈來的 ‘編譯時(shí)’ 這個(gè)概念到底是發(fā)生在什么時(shí)候? 它都做了什么工作闪萄?
后來在看了一些書籍以及度娘之后終于有所領(lǐng)悟梧却,為防止自己日后再次遺忘,特別記錄在這里败去。

其實(shí)對(duì)于js的編譯期或者說預(yù)編譯放航,我自己是一直都知道的,只是自己沒有把這個(gè) 動(dòng)作 跟j s的編譯聯(lián)系到一塊兒而已圆裕。直接上例子??

劇透: 其實(shí)你想象j s中的hosting(變量提升)就懂了
理解預(yù)編譯首先要弄清楚兩個(gè)概念: 函數(shù)聲明和變量賦值
function xiaoyu() {} // 函數(shù)聲明 這種形式的寫法是函數(shù)聲明广鳍,也即是聲明一個(gè)函數(shù),這種寫法吓妆,腳本在執(zhí)行之前會(huì)做預(yù)編譯處理(這里很重要哦赊时,要記得函數(shù)聲明是會(huì)有一個(gè)高的優(yōu)先級(jí)的先編譯后執(zhí)行)
再來看另一種寫法:
var xiaoyu = function() {} // 變量賦值
這種寫法就屬于是變量的賦值了,函數(shù)在js中也是一種數(shù)據(jù)行拢,匿名函數(shù)作為變量賦值給定義的變量祖秒。這種形式的寫法,在編譯階段也會(huì)做處理,但是但是但是but只會(huì)給變量xiaoyu分配一個(gè)內(nèi)存空間竭缝,不會(huì)初始化(好吧房维,初始化為undefined了)具體值的初始化是在程序執(zhí)行階段。
好了接下來就可以正式看例子了:
??1:
function xiaoyu() {
alert('xiaoyu')
}
xiaoyu()
function xiaoyu() {
alert('xiaoyu2')
}
xiaoyu()
分析這段代碼抬纸,首先判斷兩個(gè)都屬于是函數(shù)聲明咙俩,都會(huì)在預(yù)編譯階段處理,而函數(shù)名相同松却,后面聲明的會(huì)覆蓋前面的在執(zhí)行階段就只會(huì)看到后面的暴浦。所以將代碼復(fù)制到控制臺(tái)執(zhí)行會(huì)看到兩個(gè)xiaoyu2
??2:
var xiaoyu = function () {alert('xiaoyu')}
xiaoyu()
xiaoyu = function(){alert('xiaoyu2')}
xiaoyu()
分析代碼,首先判斷兩個(gè)都屬于是變量賦值晓锻,而且兩個(gè)變量名一樣歌焦,所以在編譯階段只會(huì)分配一個(gè)內(nèi)存空間存放變量xiaoyu的內(nèi)容,當(dāng)代碼執(zhí)行時(shí)候按照順序執(zhí)行和賦值砚哆,會(huì)先后彈出xiaoyu 和xiaoyu2
var xiaoyu // undefined
xiaoyu = function () {alert('xiaoyu')}
xiaoyu() // 'xiaoyu'
xiaoyu = function(){alert('xiaoyu2')}
xiaoyu() // 'xiaoyu2'
明白了吧
??3:
function xiaoyu() {alert('xiaoyu')}
xiaoyu()
xiaoyu = function() {alert('xiaoyu2')}
xiaoyu()
分析代碼独撇,首先第一個(gè)屬于函數(shù)聲明,后一種屬于變量賦值躁锁。所以預(yù)編譯處理完后代碼應(yīng)該是這樣的:
var xiaoyu // undefined
function xiaoyu() {alert('xiaoyu')}
xiaoyu() // 'xiaoyu'
xiaoyu = function() {alert('xiaoyu2')}
xiaoyu() // 'xiaoyu2'
??4:

window.alert(xiaoyu)
function xiaoyu() {}
window.alert(xiaoyu)
var xiaoyu = 123
以上代碼編譯結(jié)束應(yīng)該是這樣的:
var xiaoyu // undefined
function xiaoyu () {alert('xiaoyu')}
window.alert(xiaoyu) // function xiaoyu() {}
window.alert(xiaoyu) // function xiaoyu() {}
xiaoyu = 123

總結(jié)可以得出纷铣,函數(shù)聲明和變量聲明會(huì)在預(yù)編譯階段被’提升‘并且變量的提升是被最優(yōu)先的提升的,也就是說如果一個(gè)函數(shù)聲明一個(gè)和一個(gè)變量同名了比如例子三中的那么變量名會(huì)被優(yōu)先提升到最高 var xiaoyu // 不賦值 為undefined 然后提升函數(shù)聲明 function xiaoyu() {alert('xiaoyu')} // 此時(shí)因?yàn)楹瘮?shù)聲明在后所以它覆蓋了xiaoyu變量給它復(fù)制為一個(gè)函數(shù)战转。當(dāng)js引擎做完所有的這些提升的工作后js才會(huì)按照代碼順序來執(zhí)行搜立。

另外需要注意的是 js不是全文編譯完成再執(zhí)行,而是塊編譯槐秧,即一個(gè)script塊中預(yù)編譯然后執(zhí)行啄踊,再按順序預(yù)編譯下一個(gè)script塊再執(zhí)行 但是此時(shí)上一個(gè)script快中的數(shù)據(jù)都是可用的了,而下一個(gè)塊中的函數(shù)和變量則是不可用的刁标。

OK 講到這里颠通,是不是有點(diǎn)懂得es6中大編譯時(shí)執(zhí)行是什么意思了,它就是在代碼執(zhí)行前做的一個(gè)預(yù)編譯也可以叫做靜態(tài)編譯膀懈,好處是讓你可以在執(zhí)行任何代碼前預(yù)初始化更多的模塊結(jié)構(gòu)顿锰,這樣如果引用尚未賦值的export,能得到更好的錯(cuò)誤信息启搂。例如硼控,一個(gè)let綁定會(huì)扔出異常——如果你在它被賦值之前就引用它的話——你可以得到清晰的錯(cuò)誤信息胳赌。而一個(gè)動(dòng)態(tài)模塊對(duì)象上的屬性如果還未賦值就被引用牢撼,得到的是undefined,最終錯(cuò)誤可能發(fā)生在客戶代碼中匈织,必須跟蹤這個(gè)錯(cuò)誤直到源頭——這比異常要難調(diào)試太多了。

累了,先寫到這里

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缀匕,一起剝皮案震驚了整個(gè)濱河市纳决,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乡小,老刑警劉巖阔加,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異满钟,居然都是意外死亡胜榔,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門湃番,熙熙樓的掌柜王于貴愁眉苦臉地迎上來夭织,“玉大人,你說我怎么就攤上這事吠撮∽鸲瑁” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵泥兰,是天一觀的道長弄屡。 經(jīng)常有香客問我,道長鞋诗,這世上最難降的妖魔是什么膀捷? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮削彬,結(jié)果婚禮上全庸,老公的妹妹穿的比我還像新娘。我一直安慰自己吃警,他們只是感情好糕篇,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著酌心,像睡著了一般拌消。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上安券,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天墩崩,我揣著相機(jī)與錄音,去河邊找鬼侯勉。 笑死鹦筹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的址貌。 我是一名探鬼主播铐拐,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼徘键,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了遍蟋?” 一聲冷哼從身側(cè)響起吹害,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎虚青,沒想到半個(gè)月后它呀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡棒厘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年纵穿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奢人。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谓媒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出达传,到底是詐尸還是另有隱情篙耗,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布宪赶,位于F島的核電站宗弯,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏搂妻。R本人自食惡果不足惜蒙保,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望欲主。 院中可真熱鬧邓厕,春花似錦、人聲如沸扁瓢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽引几。三九已至昧互,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間伟桅,已是汗流浹背敞掘。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留楣铁,地道東北人玖雁。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像盖腕,于是被迫代替她去往敵國和親赫冬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子浓镜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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