瀏覽器中的JavaScript代碼執(zhí)行機(jī)制

1.變量提升

JavaScript代碼在執(zhí)行的時(shí)候铃拇,利用var聲明的變量是會(huì)提升到代碼的開頭并且賦值為unddefined钞瀑。
使用函數(shù)聲明創(chuàng)建的函數(shù)也會(huì)被提升,稱為函數(shù)提升慷荔。
上述兩個(gè)機(jī)制的存在使得我們可以在變量和函數(shù)聲明之前使用它們雕什。
JavaScript代碼會(huì)經(jīng)過JavaScript引擎的編譯之后再執(zhí)行。代碼經(jīng)過編譯之后显晶,會(huì)生成包含變量對象和詞法環(huán)境的執(zhí)行上下文以及可執(zhí)行代碼贷岸。變量對象中保存的就是被提升的變量聲明和函數(shù)聲明。如果遇到var聲明的變量吧碾,變量對象中就會(huì)生成一個(gè)屬性名為變量名凰盔、屬性值為undefined的屬性;如果遇到函數(shù)聲明倦春,就會(huì)生成一個(gè)方法名為函數(shù)名,方法為函數(shù)本身的方法(函數(shù)存儲(chǔ)在堆內(nèi)存中落剪,方法名保留的是地址值睁本。)
簡單總結(jié)執(zhí)行機(jī)制。

  1. 編譯忠怖。進(jìn)行變量和函數(shù)聲明的提升呢堰,存儲(chǔ)在變量對象中。
  2. 執(zhí)行凡泣。順序執(zhí)行可執(zhí)行的代碼枉疼。

2.調(diào)用棧

JavaScript引擎在執(zhí)行代碼的時(shí)候,會(huì)創(chuàng)建執(zhí)行上下文鞋拟。主要有全局執(zhí)行上下文骂维,函數(shù)執(zhí)行上下文和eval函數(shù)的執(zhí)行上下文。首先在執(zhí)行JavaScript代碼前贺纲,就會(huì)創(chuàng)建一個(gè)全局執(zhí)行上下文壓入棧航闺,然后根據(jù)函數(shù)的調(diào)用順序依次將執(zhí)行上下文壓入棧。函數(shù)內(nèi)部代碼被執(zhí)行完畢猴誊,對應(yīng)的執(zhí)行上下文就會(huì)被彈出棧潦刃。
執(zhí)行上下文中包含變量對象(VO)和詞法環(huán)境兩個(gè)部分,執(zhí)行上下文是在JavaScript引擎編譯階段創(chuàng)建的懈叹,也就是代碼執(zhí)行前乖杠。
一段代碼

    var a = 2
    function add(b,c){
        return b+c
    }
    function addAll(b,c){
        var d = 10
        result = add(b,c)
        return  a+result+d
    }
    addAll(3,6)

在開發(fā)者工具中給代碼打上斷點(diǎn)之后,在右邊的調(diào)用棧堆里面能看見目前調(diào)用棧中的執(zhí)行上下文有哪些澄成。



或者給代碼加上一個(gè)console.trace也可以胧洒。

    var a = 2
    function add(b,c){
        console.trace()//查看函數(shù)調(diào)用關(guān)系
        return b+c
    }
    function addAll(b,c){
        var d = 10
        result = add(b,c)
        return  a+result+d
    }
    addAll(3,6)

控制臺(tái)輸出結(jié)果:



棧溢出問題笆包,執(zhí)行上下文的調(diào)用棧是有大小的。如果創(chuàng)建一個(gè)遞歸函數(shù)并且不設(shè)置終止條件略荡,最終就會(huì)發(fā)生棧溢出庵佣。為避免棧溢出,需要盡量將遞歸任務(wù)分解成其他的小型任務(wù)來執(zhí)行汛兜。

3.塊級(jí)作用域

ES6之前JavaScript只有全局作用域和函數(shù)作用域巴粪,ES6通過let和const實(shí)現(xiàn)了塊級(jí)作用域。簡單來說一對大括號(hào)就是一個(gè)塊級(jí)作用域粥谬。ES6如何同時(shí)支持變量提升和塊級(jí)作用域肛根?
前面提到,函數(shù)調(diào)用時(shí)會(huì)創(chuàng)建執(zhí)行上下文漏策,執(zhí)行上下文中有兩個(gè)部分派哲,變量對象和詞法環(huán)境。支持塊級(jí)作用域?qū)嶋H上就是通過詞法環(huán)境實(shí)現(xiàn)的掺喻。比如下面這個(gè)代碼:

function foo(){
    var a = 1
    let b = 2
    {
      let b = 3
      var c = 4
      let d = 5
      console.log(a)
      console.log(b)
    }
    console.log(b) 
    console.log(c)
    console.log(d)
}   
foo()

來分析一下這段代碼的如何執(zhí)行芭届,以及執(zhí)行上下文的情況。

  • 1.調(diào)用函數(shù)感耙,創(chuàng)建執(zhí)行上下文褂乍。變量對象中有a,c兩個(gè)變量,值都是undefined(var聲明的變量的變量提升導(dǎo)致的)即硼。詞法環(huán)境中有一個(gè)變量b逃片,但是由于let會(huì)生成暫時(shí)性死區(qū),所以雖然b已經(jīng)存在了只酥,但是在聲明b之前的語句去訪問b瀏覽器都會(huì)報(bào)錯(cuò)褥实。
  • 2.執(zhí)行大括號(hào)內(nèi)部代碼,此時(shí)a=1,b=2裂允。此時(shí)由于進(jìn)入了一個(gè)新的作用域塊损离,所以詞法環(huán)境中會(huì)將這個(gè)塊壓入棧,這個(gè)新的塊中也有兩個(gè)變量b,d叫胖,同樣在它們聲明之前不可訪問草冈。
  • 3.console.log(a)。執(zhí)行這句代碼的時(shí)候瓮增,就涉及到了如何在詞法環(huán)境和變量對象中尋找變量了怎棱。首先會(huì)查找位于詞法環(huán)境的棧頂?shù)膲K中的變量,然后沿著這個(gè)順序一直向下查找到位于棧底的塊绷跑,如果都沒有找到則會(huì)進(jìn)入變量對象中去尋找變量拳恋。也就是說,優(yōu)先在詞法環(huán)境中尋找砸捏,其后再到變量對象中尋找谬运。

4.作用域和閉包

作用域隙赁。始終記住作用域是靜態(tài)的,并且作用域在函數(shù)被定義的時(shí)候就已經(jīng)是確定了的梆暖,不會(huì)再發(fā)生改變了伞访。
閉包。記住閉包產(chǎn)生的兩個(gè)條件轰驳,函數(shù)嵌套以及內(nèi)部的函數(shù)引用了外部函數(shù)的變量厚掷。有了閉包,即使外部函數(shù)已經(jīng)執(zhí)行完畢级解,它的執(zhí)行上下文也已經(jīng)被彈出了執(zhí)行棧冒黑,但是內(nèi)部的變量還是會(huì)被保留下來,當(dāng)內(nèi)部函數(shù)被調(diào)用勤哗,這些被保存的變量隨時(shí)可以被這個(gè)內(nèi)部函數(shù)調(diào)用抡爹。就像一個(gè)專屬于內(nèi)部函數(shù)的背包一樣。
閉包的存在使得變量查找的作用域鏈發(fā)生了一定變化芒划。首先會(huì)在內(nèi)部函數(shù)自身的執(zhí)行上下文中尋找冬竟,之后進(jìn)入閉包中尋找,最后進(jìn)入全局作用域?qū)ふ摇?/p>

5.this

  1. 函數(shù)直接以函數(shù)形式被調(diào)用的時(shí)候腊状,this指向全局對象window
  2. call apply bind可以修改函數(shù)的this指向诱咏,使其指向參數(shù)中的對象
  3. 作為對象的方法被調(diào)用的時(shí)候,指向調(diào)用該方法的對象
  4. 構(gòu)造函數(shù)形式被調(diào)用缴挖,this指向利用構(gòu)造函數(shù)創(chuàng)建的對象
  5. 箭頭函數(shù)的this是靜態(tài)的,指向其被創(chuàng)建時(shí)所在的對象
    嵌套函數(shù)焚辅,內(nèi)部的函數(shù)不會(huì)繼承外部函數(shù)的this指向

6.小結(jié)

本節(jié)重點(diǎn):

  1. JavaScript代碼也是需要先編譯后執(zhí)行的映屋,編譯的工作由JavaScript引擎來完成。
  2. 代碼經(jīng)過編譯后會(huì)生成執(zhí)行上下文和可執(zhí)行代碼同蜻,執(zhí)行上下文中由變量對象和詞法環(huán)境棚点。也解釋了為什么JavaScript會(huì)存在變量提升,其實(shí)是JavaScript引擎編譯的鍋湾蔓。
  3. var聲明和函數(shù)聲明的變量和函數(shù)會(huì)被存儲(chǔ)在變量環(huán)境中瘫析,變量的初始化值是undefined,函數(shù)則是函數(shù)的定義默责。let,const聲明的變量被存儲(chǔ)在詞法環(huán)境中贬循,形成暫時(shí)性死區(qū),也就是在聲明變量前不能對他們進(jìn)行訪問桃序。
  4. 每進(jìn)入一個(gè)新的代碼塊杖虾。詞法環(huán)境會(huì)創(chuàng)建一個(gè)新的塊壓入棧,里面是這個(gè)代碼塊中使用let和const聲明的變量媒熊。
  5. JavaScript尋找變量的方式奇适。首先在詞法環(huán)境棧頂?shù)膲K中尋找坟比,然后依次向下到棧底的塊,最后再到變量對象中尋找嚷往。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末葛账,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子皮仁,更是在濱河造成了極大的恐慌籍琳,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件魂贬,死亡現(xiàn)場離奇詭異巩割,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)付燥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門宣谈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人键科,你說我怎么就攤上這事闻丑。” “怎么了勋颖?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵嗦嗡,是天一觀的道長。 經(jīng)常有香客問我饭玲,道長侥祭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任茄厘,我火速辦了婚禮矮冬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘次哈。我一直安慰自己胎署,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布窑滞。 她就那樣靜靜地躺著琼牧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哀卫。 梳的紋絲不亂的頭發(fā)上丽涩,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天萄唇,我揣著相機(jī)與錄音挑围,去河邊找鬼雏蛮。 笑死,一個(gè)胖子當(dāng)著我的面吹牛带斑,可吹牛的內(nèi)容都是我干的鼓寺。 我是一名探鬼主播勋拟,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼妈候!你這毒婦竟也來了敢靡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤苦银,失蹤者是張志新(化名)和其女友劉穎啸胧,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體幔虏,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡纺念,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了想括。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陷谱。...
    茶點(diǎn)故事閱讀 39,703評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖瑟蜈,靈堂內(nèi)的尸體忽然破棺而出烟逊,到底是詐尸還是另有隱情,我是刑警寧澤铺根,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布宪躯,位于F島的核電站,受9級(jí)特大地震影響位迂,放射性物質(zhì)發(fā)生泄漏访雪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一掂林、第九天 我趴在偏房一處隱蔽的房頂上張望冬阳。 院中可真熱鬧,春花似錦党饮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至饲常,卻和暖如春蹲堂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贝淤。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工柒竞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人播聪。 一個(gè)月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓朽基,卻偏偏與公主長得像布隔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子稼虎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評論 2 353

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