昨天碰到一不好“對(duì)付”人,問(wèn)了我這個(gè)問(wèn)題~~
我查了,大家都是討論什么是變量提升和函數(shù)提升。。。
于是,我仔細(xì)想了一下,有什么好問(wèn)的呢,能告訴自己的解釋就是:為了體現(xiàn)它的作用域?使其在作用域內(nèi)有效....
請(qǐng)問(wèn)哪位有沒(méi)有更好、更深、更全面的解釋~~比如涉及到j(luò)s底層存儲(chǔ)之類(lèi)
我覺(jué)得你想問(wèn)的應(yīng)該是JS為什么要進(jìn)行變量提升,而不是按照順序解析和綁定變量這么一個(gè)問(wèn)題吧?
好,下面就談?wù)勎覍?duì)這個(gè)問(wèn)題的看法。
首先,我們都知道,JS拿到一段代碼或一個(gè)函數(shù)的時(shí)候,會(huì)有兩步主要操作,即解析與執(zhí)行。
在解析階段,JS會(huì)檢查語(yǔ)法,并對(duì)函數(shù)進(jìn)行預(yù)編譯。
所以當(dāng)函數(shù)的代碼有語(yǔ)法錯(cuò)誤的時(shí)候,在函數(shù)執(zhí)行前就會(huì)報(bào)錯(cuò)(SyntaxError)。
接下來(lái)是執(zhí)行階段,這個(gè)階段沒(méi)什么好講的,就是逐條解釋每條語(yǔ)句并執(zhí)行。
弄明白JS函數(shù)的兩個(gè)階段之后,下面我們就來(lái)談?wù)劼暶魈嵘膯?wèn)題。聲明提升就是函數(shù)中任何位置所聲明的變量或函數(shù),都會(huì)自動(dòng)“提”到函數(shù)的最前面,就好像它們是在函數(shù)的開(kāi)頭聲明的一樣。
為什么要提升變量和函數(shù)的聲明?表面上看,是因?yàn)樽饔糜?。確實(shí),在ES6之前,JS并沒(méi)有塊級(jí)作用域,所有變量要么具有全局作用域,要么具有函數(shù)級(jí)作用域。
但是進(jìn)一步思考就會(huì)發(fā)現(xiàn),這只是聲明提升的結(jié)果,而不能成為必須要這么做的理由。后來(lái)加入的let變量就是一個(gè)例子。
那么究竟為什么要進(jìn)行聲明提升呢?其實(shí)我認(rèn)為主要原因有兩點(diǎn):
前面說(shuō)過(guò),JS會(huì)在函數(shù)執(zhí)行前對(duì)其進(jìn)行語(yǔ)法檢查和預(yù)編譯,并且這一操作只會(huì)進(jìn)行一次。之所以要這么做,一個(gè)目的在于提高性能。因?yàn)槿绻麤](méi)有這一步,那么每次執(zhí)行函數(shù)前都必須重新解析一遍該函數(shù),而這是沒(méi)有必要的,因?yàn)楹瘮?shù)的代碼并不會(huì)改變,解析一遍就夠了。
另外,解析的過(guò)程中,還會(huì)為函數(shù)生成預(yù)編譯代碼。在預(yù)編譯時(shí),會(huì)統(tǒng)計(jì)該函數(shù)聲明了哪些變量、創(chuàng)建了哪些函數(shù)(注:這里就是聲明提升),并對(duì)函數(shù)的代碼進(jìn)行壓縮,去除注釋、不必要的空白等。這樣做的好處是每次執(zhí)行函數(shù)時(shí)都可以直接為該函數(shù)分配??臻g(不需要再解析一遍去獲取函數(shù)中聲明了哪些變量,注:這也是聲明提升的好處),并且代碼執(zhí)行更快(因?yàn)閴嚎s而變短了)。兩個(gè)好處都會(huì)提高執(zhí)行函數(shù)的性能。
我們知道,JS是一種腳本語(yǔ)言,在發(fā)布之后很長(zhǎng)時(shí)間內(nèi)都沒(méi)有為程序員提供編譯器、調(diào)試器、語(yǔ)法檢查器等工具。在很長(zhǎng)一段時(shí)間內(nèi)其地位始終是Web頁(yè)面的附屬品,僅僅用來(lái)給頁(yè)面添加一些非必要的動(dòng)態(tài)效果,并且其開(kāi)發(fā)和部署也具有很強(qiáng)的隨意性,未經(jīng)過(guò)調(diào)試和測(cè)試的代碼比比皆是。直到后來(lái)Ajax的出現(xiàn),這一情況才逐步改變。
在這種情況下,提高JS的容錯(cuò)就是很有好處的了。而聲明提升可以在一定程度上提高JS的容錯(cuò)性??聪旅娴睦樱?/p>
function foo() {
console.log(a);
var a;
}
如果沒(méi)有聲明提升,這段代碼就是錯(cuò)的,但有了聲明提升,這段代碼便可以正常運(yùn)行。
但是你可能會(huì)說(shuō),正常代碼不應(yīng)該這么寫(xiě),就像其他語(yǔ)言,變量肯定要先聲明再使用啊,因此這一點(diǎn)只要稍加注意就能避免,不是嗎?
確實(shí)如此,但稍加注意也要投入注意力不是?尤其是在修改別人的代碼的時(shí)候,這種在聲明前就使用的情況就更容易發(fā)生了。
如果上面的例子無(wú)法說(shuō)服你,下面再看一個(gè)更有代表性的例子:
function foo() {
if (...) {
var a;
}
console.log(a);
}
這種情況更常見(jiàn)了,在寫(xiě)if語(yǔ)句的時(shí)候,我發(fā)現(xiàn)我需要一個(gè)變量a,于是順手寫(xiě)了var a = ...;,但是到后面我又發(fā)現(xiàn)這個(gè)變量在if語(yǔ)句外面也會(huì)用到,于是我忘記了回頭去把a(bǔ)的聲明提到if外面。當(dāng)if的條件不滿(mǎn)足的時(shí)候,里面的代碼根本不會(huì)執(zhí)行,如果沒(méi)有聲明提升,那么這時(shí)候a將不會(huì)存在。
而要在代碼層面完全避免這種情況顯然需要投入更多的注意力才行了。當(dāng)然,你可能會(huì)說(shuō),這個(gè)好像不是聲明提升,變量a本來(lái)就是在使用前定義的啊。
這么說(shuō)沒(méi)有錯(cuò),但是你不能不承認(rèn)JS的變量沒(méi)有塊作用域這一事實(shí)與聲明提升有很大關(guān)系。比如,如果把var a換成let a。
總結(jié):
北大青鳥(niǎo)APTECH成立于1999年。依托北京大學(xué)優(yōu)質(zhì)雄厚的教育資源和背景,秉承“教育改變生活”的發(fā)展理念,致力于培養(yǎng)中國(guó)IT技能型緊缺人才,是大數(shù)據(jù)專(zhuān)業(yè)的國(guó)家
達(dá)內(nèi)教育集團(tuán)成立于2002年,是一家由留學(xué)海歸創(chuàng)辦的高端職業(yè)教育培訓(xùn)機(jī)構(gòu),是中國(guó)一站式人才培養(yǎng)平臺(tái)、一站式人才輸送平臺(tái)。2014年4月3日在美國(guó)成功上市,融資1
北大課工場(chǎng)是北京大學(xué)校辦產(chǎn)業(yè)為響應(yīng)國(guó)家深化產(chǎn)教融合/校企合作的政策,積極推進(jìn)“中國(guó)制造2025”,實(shí)現(xiàn)中華民族偉大復(fù)興的升級(jí)產(chǎn)業(yè)鏈。利用北京大學(xué)優(yōu)質(zhì)教育資源及背
博為峰,中國(guó)職業(yè)人才培訓(xùn)領(lǐng)域的先行者
曾工作于聯(lián)想擔(dān)任系統(tǒng)開(kāi)發(fā)工程師,曾在博彥科技股份有限公司擔(dān)任項(xiàng)目經(jīng)理從事移動(dòng)互聯(lián)網(wǎng)管理及研發(fā)工作,曾創(chuàng)辦藍(lán)懿科技有限責(zé)任公司從事總經(jīng)理職務(wù)負(fù)責(zé)iOS教學(xué)及管理工作。
浪潮集團(tuán)項(xiàng)目經(jīng)理。精通Java與.NET 技術(shù), 熟練的跨平臺(tái)面向?qū)ο箝_(kāi)發(fā)經(jīng)驗(yàn),技術(shù)功底深厚。 授課風(fēng)格 授課風(fēng)格清新自然、條理清晰、主次分明、重點(diǎn)難點(diǎn)突出、引人入勝。
精通HTML5和CSS3;Javascript及主流js庫(kù),具有快速界面開(kāi)發(fā)的能力,對(duì)瀏覽器兼容性、前端性能優(yōu)化等有深入理解。精通網(wǎng)頁(yè)制作和網(wǎng)頁(yè)游戲開(kāi)發(fā)。
具有10 年的Java 企業(yè)應(yīng)用開(kāi)發(fā)經(jīng)驗(yàn)。曾經(jīng)歷任德國(guó)Software AG 技術(shù)顧問(wèn),美國(guó)Dachieve 系統(tǒng)架構(gòu)師,美國(guó)AngelEngineers Inc. 系統(tǒng)架構(gòu)師。