如果你是一個(gè)前端工程師,那么JavaScript作用域你一定不會(huì)陌生。你知道的可能是 JavaScript中有: 傳統(tǒng)的函數(shù)級(jí)作用域和全局作用域、ES6 let const 的塊級(jí)作用域。但是還有一個(gè)你不知道的塊級(jí)作用域的存在,今天我們就來(lái)扒一扒這些鮮為人知的小秘密我們先來(lái)看看下面這個(gè)段代碼,請(qǐng)思考一下結(jié)果是什么。
想必你心中已經(jīng)有了結(jié)果
正確答案是3 2
你答對(duì)了嗎?答案結(jié)果是否有些意外呢?好了,我們來(lái)看看為什么會(huì)出現(xiàn)這個(gè)答案首先我們需要先了解以下基本知識(shí)
聲明提前
聲明提前指的是JS引擎在執(zhí)行之前對(duì)代碼進(jìn)行的預(yù)解析(為了提高執(zhí)行效率) 具體的來(lái)說(shuō)就是使用(var)聲明變量和(function)聲明的函數(shù)正預(yù)編譯階段將其提升到了作用域的頂部
全局變量聲明
函數(shù)作用域變量聲明
函數(shù)聲明
函數(shù)表達(dá)式聲明
函數(shù)塊級(jí)作用域
通過(guò)下面代碼我們可以知道 變量的聲明是沒(méi)有塊級(jí)作用域的,if語(yǔ)句塊中聲明的變量foo會(huì)提升到全局作用域并初始化值為undefined
我們?cè)倏纯春瘮?shù)的情況
上面這個(gè)例子告訴我們 函數(shù)foo提升到了if語(yǔ)句塊的頂部,但是沒(méi)有提升到全局作用域的頂部。但全局作用域中存有一個(gè)名為foo的變量 在代碼執(zhí)行后同步成了函數(shù)foo
同步?為什么會(huì)有同步?我們來(lái)看看觀(guān)察上帝視角的神器 ———— 斷點(diǎn)調(diào)試
我這邊監(jiān)聽(tīng)了 foo 變量和 window.foo 大家請(qǐng)注意一下它的變化
同時(shí)我們也關(guān)注一下 Scope 作用域
我們看到Scope中只有全局作用域 foo和window.foo的只都是undefined
代碼執(zhí)行到if語(yǔ)句塊中 我們?cè)賁cope中又發(fā)現(xiàn)了一個(gè)新的塊級(jí)作用域 當(dāng)前塊級(jí)作用域foo的值被賦值為一個(gè)函數(shù)(函數(shù)提升) 而全局作用域中的foo依舊是undefined
代碼繼續(xù)往后執(zhí)行 執(zhí)行函數(shù)的賦值 block作用域依然存在 我把幾個(gè)變量的值使用箭頭進(jìn)行了對(duì)應(yīng)
神奇的地方來(lái)了 在函數(shù)執(zhí)行賦值后 塊級(jí)作用域消失 而全局變量的foo同步成了剛才塊級(jí)作用域的foo
回歸原題
我們對(duì)foo變量進(jìn)行隔行輸出 看看結(jié)果
結(jié)合上面斷點(diǎn)測(cè)試的結(jié)果大家可以發(fā)現(xiàn),函數(shù)在代碼塊中聲明會(huì)提前到塊級(jí)作用域頂部,預(yù)編譯結(jié)束后開(kāi)始執(zhí)行代碼 在執(zhí)行階段任然會(huì)執(zhí)行函數(shù)的賦值操作,其實(shí)是函數(shù)賦值的第二次執(zhí)行(第一次在預(yù)編譯階段) 第二次的賦值執(zhí)行的意義是確認(rèn)當(dāng)前 函數(shù)/全局 作用域能準(zhǔn)確的檢索到函數(shù) 所以講函數(shù)同步到了 當(dāng)前的函數(shù)或全局作用域中。更多關(guān)于前端培訓(xùn)的問(wèn)題,歡迎咨詢(xún)千鋒教育在線(xiàn)名師,如果想要了解我們的師資、課程、項(xiàng)目實(shí)操的話(huà)可以點(diǎn)擊咨詢(xún)課程顧問(wèn),獲取試聽(tīng)資格來(lái)試聽(tīng)我們的課程,在線(xiàn)零距離接觸千鋒教育大咖名師,讓你輕松從入門(mén)到精通。
注:本文部分文字和圖片來(lái)源于網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系刪除。版權(quán)歸原作者所有!