js變量的聲明提升和函數(shù)的聲明提升

Js代碼分為兩個(gè)階段:編譯階段和執(zhí)行階段

Js代碼的編譯階段會(huì)找到所有的聲明,并用合適的作用域?qū)⑺鼈冴P(guān)聯(lián)起來莲镣。

包括變量聲明(var a)和函數(shù)聲明(function a(){})在內(nèi)的所有聲明都會(huì)在代碼被執(zhí)行前的編譯階段首先被處理诈嘿。這個(gè)過程就好像變量聲明和函數(shù)聲明從他們代碼中出現(xiàn)的位置被添加到最近執(zhí)行環(huán)境的頂部述呐,這個(gè)過程就叫做提升(hoisting)篮迎。

只有聲明操作會(huì)被提升甫菠,賦值和邏輯操作會(huì)被留在原地等待執(zhí)行仔粥。

變量的聲明

js中婴谱,在使用一個(gè)變量之前應(yīng)當(dāng)先聲明蟹但。變量是使用關(guān)鍵字var聲明的,如:

var i;

var sum;

注:此時(shí)console.log(i)=undefined谭羔,因?yàn)榇藭r(shí)的變量沒有被賦值华糖,默認(rèn)初始值是undefined。

也可以使用一個(gè)var關(guān)鍵字聲明多個(gè)變量:

var i,sum;

而且還可以將變量的初始賦值和變量聲明合寫在一起:

var m="hello";

var i = 0,j = 0,k = 0;

到這里你大概會(huì)發(fā)現(xiàn)js的變量聲明中沒有指定數(shù)據(jù)類型瘟裸,就比如在C語言中客叉,我們定義一個(gè)變量常常是int a;char c;。话告。兼搏。。這里的int char 就是所謂的數(shù)據(jù)類型

小知識(shí):編程語言分為動(dòng)態(tài)(類型)語言和靜態(tài)(類型)語言沙郭,動(dòng)態(tài)類型語言是指在運(yùn)行期間才會(huì)去做數(shù)據(jù)類型檢查的語言佛呻,也就是說,在用動(dòng)態(tài)類型的語言編程的時(shí)病线,永遠(yuǎn)也不用給任何變量指定數(shù)據(jù)類型吓著,該語言會(huì)在第一次賦值給變量時(shí),在內(nèi)部將數(shù)據(jù)類型記錄下來送挑。靜態(tài)類型語言與動(dòng)態(tài)類型語言剛好相反绑莺,它的數(shù)據(jù)類型是在編譯期間檢查的,也就是說在寫程序時(shí)要聲明所有變量的數(shù)據(jù)類型让虐。

靜態(tài)類型語言:C/C++紊撕、C#、JAVA等

動(dòng)態(tài)類型語言:Python赡突、Ruby、JavaScript等

變量聲明提升

舉個(gè)例子:

var a = 1;

var b =2;

上述兩行代碼在編譯時(shí)区赵,實(shí)際上它的順序是這樣的:

var a;? ? //undefined

var b;? ? //undefined

a = 1;? ? //1

b = 2;? ? //2

解釋:編譯器將var a = 1;這行代碼分成兩步操作惭缰,

第一步是變量的聲明提升:var a;聲明操作會(huì)在編譯階段進(jìn)行笼才,所有聲明會(huì)被提升到最近執(zhí)行環(huán)境的頂部漱受,此時(shí)的變量值是初始值undefined。

第二步是常規(guī)的賦值操作:a = 0;

這里有一點(diǎn)要注意骡送,JavaScript中聲明變量可以不寫前面的var關(guān)鍵字昂羡,這種是合法且可行的,去掉var時(shí)摔踱,會(huì)被默認(rèn)成全局變量虐先,但是我們不建議這樣使用,這個(gè)不好的習(xí)慣會(huì)造成很多bug派敷。嚴(yán)格模式下蛹批,不聲明就使用一個(gè)變量也會(huì)導(dǎo)致錯(cuò)誤撰洗。比如:

function add(num1,num2){

var sum = num1 + num2;

return sum;

}

var result = add(10,20);? ? ? //30

alert(sum);? ? ? ? ? ? ? ? ? ? ? ? //由于sum在函數(shù)體內(nèi)被聲明過,在全局不是有效的變量腐芍,因此會(huì)導(dǎo)致錯(cuò)誤

改成:

function add(num1,num2){

sum = num1 + num2;

return sum;

}

var result = add(10,20);? ? ? //30

alert(sum);? ? ? ? ? ?//30 此時(shí)的sum是全局變量差导,所以這里可以訪問的到。但是不推薦猪勇。

函數(shù)的聲明

定義函數(shù)有三種方式:函數(shù)聲明设褐、函數(shù)表達(dá)式、Function構(gòu)造函數(shù)(不推薦)

函數(shù)聲明提升會(huì)在編譯階段把聲明和函數(shù)體整體都提前到執(zhí)行環(huán)境頂部泣刹,所以我們可以在函數(shù)聲明之前調(diào)用這個(gè)函數(shù)助析。比如:

function sum(num1,num2){

return num1 + num2;

}

函數(shù)表達(dá)式,其實(shí)就是變量聲明的一種项玛,聲明操作會(huì)被提升到執(zhí)行環(huán)境頂部貌笨,并賦值undefined。賦值操作被留在原地等到執(zhí)行襟沮。這種定義方式得到的函數(shù)也叫匿名函數(shù)(拉姆達(dá)函數(shù))锥惋,因?yàn)閒unction關(guān)鍵字后面沒有函數(shù)名字,只是把這個(gè)函數(shù)體賦值給一個(gè)變量开伏。這種方式定義函數(shù)也沒有必要使用函數(shù)名---通過變量名就可以引用函數(shù)膀跌。另外還要注意,此時(shí)函數(shù)末尾有一個(gè)分號(hào)固灵,就像聲明其他變量一樣需要一個(gè)分號(hào)作為結(jié)尾捅伤。比如:

var sum = function (num1,num2){

return num1 + num2;

};

Function構(gòu)造函數(shù)可以接收任意數(shù)量的參數(shù),但最后一個(gè)參數(shù)始終都被看成函數(shù)體巫玻,而前面的參數(shù)枚舉出了新函數(shù)的參數(shù)丛忆。比如:

var sum = new Function("num1","num2","return num1 + num2");? ? ? ? //不推薦

從技術(shù)上講,這是一個(gè)函數(shù)表達(dá)式仍秤,但是這種語法會(huì)導(dǎo)致解析兩次代碼(第一次是解析常規(guī)的ES代碼熄诡,第二次是解析傳入構(gòu)造函數(shù)中的字符串),從而影響性能诗力。不過凰浮,這種語法對(duì)于理解“函數(shù)是對(duì)象,函數(shù)名是指針”的概念倒是非常直觀的苇本。

函數(shù)的聲明提升

小知識(shí):在一些類似C語言的編程語言中袜茧,花括號(hào)內(nèi)的每一段代碼都是具有各組的作用域,而且變量在聲明它們的代碼段之外是不可見的瓣窄。我們稱之為塊級(jí)作用域(block scope)笛厦,然而,JavaScript是沒有塊級(jí)作用域康栈。JavaScript取而代之地使用了函數(shù)作用域(function scope):變量在聲明它們的函數(shù)體以及這個(gè)函數(shù)體嵌套的任意函數(shù)體內(nèi)都是有定義的递递。

function test(0){

var i = 0;? ? ? ? //i在整個(gè)函數(shù)體內(nèi)均有定義

? ? if(typeof 0 == "object"){

? ? var j = 0;? //j在整個(gè)函數(shù)體內(nèi)均有定義喷橙,不僅僅是在這個(gè)代碼段內(nèi)

for(var k = 0;k < 10;k++){? //j在整個(gè)函數(shù)體內(nèi)均有定義,不僅僅是在這個(gè)循環(huán)內(nèi)

? ? ? ? console.log(k);? ? ? ? ? //輸出數(shù)字0--9

? ? }

? ? ? console.log(k);? ? ? ? ? ? ? ? ? //k已經(jīng)定義了登舞,輸出10

? ? ? ? ? }

? ? console.log(j);? ? ? ? ? ? ? ? ? ? ? ? //j已經(jīng)定義了贰逾,但可能沒有初始化

}

JavaScript的函數(shù)作用域是指在函數(shù)內(nèi)聲明的所有變量在函數(shù)體內(nèi)始終是可見的,所以當(dāng)在函數(shù)體內(nèi)使用各種for嵌套循環(huán)時(shí)應(yīng)定義不同的變量i菠秒,j疙剑,k等。

舉個(gè)例子:

var scope = "global";

function f(){

console.log(scope);? ? ? ? ? ? ? //undefined

var scope = "local";? ? ? ? ? ? ? //變量在這里賦值践叠,但是在整個(gè)函數(shù)體內(nèi)都是有定義的

console.log(scope);? ? ? ? ? ? ? //local

}? ? ? ? ?

你可能會(huì)認(rèn)為第一個(gè)console會(huì)輸出“global”言缤,但是由于函數(shù)作用域的特性,局部變量在整個(gè)函數(shù)體內(nèi)都是有定義的禁灼,上述代碼等價(jià)于:

var scope = "global";

function f(){

var scope;? ? ? ? ?//undefined管挟,因?yàn)楹瘮?shù)聲明優(yōu)先級(jí)更高,所以覆蓋了第一行的賦值

console.log(scope);? ? ? ? ? ? ? ? //變量存在弄捕,但其值是初始值undefined

scope = "local";? ? ? ? ? ? ? ? ? //變量在這里賦值為local

console.log(scope);? ? ? ? ? ? ? ? //local

}

最后總結(jié)僻孝,聲明的順序是這樣的:

第一步. 找到所有的函數(shù)聲明,初始化函數(shù)體守谓,如有同名的函數(shù)則會(huì)進(jìn)行覆蓋

第二步. 查找變量聲明穿铆,初始化為undefined,如果已經(jīng)存在同名的變量斋荞,就什么也不做直接略過荞雏。

要注意咯,函數(shù)聲明的優(yōu)先級(jí)比變量聲明的優(yōu)先級(jí)高平酿,如果是先聲明并賦值了一個(gè)變量凤优,后面的函數(shù)體內(nèi)又聲明了同名變量,此時(shí)的變量就被函數(shù)體內(nèi)的變量覆蓋了蜈彼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末别洪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子柳刮,更是在濱河造成了極大的恐慌,老刑警劉巖痒钝,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秉颗,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡送矩,警方通過查閱死者的電腦和手機(jī)蚕甥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來栋荸,“玉大人菇怀,你說我怎么就攤上這事凭舶。” “怎么了爱沟?”我有些...
    開封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵帅霜,是天一觀的道長。 經(jīng)常有香客問我呼伸,道長身冀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任括享,我火速辦了婚禮搂根,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘铃辖。我一直安慰自己剩愧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開白布娇斩。 她就那樣靜靜地躺著仁卷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪成洗。 梳的紋絲不亂的頭發(fā)上五督,一...
    開封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音瓶殃,去河邊找鬼充包。 笑死,一個(gè)胖子當(dāng)著我的面吹牛遥椿,可吹牛的內(nèi)容都是我干的基矮。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼冠场,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼家浇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起碴裙,我...
    開封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤钢悲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后舔株,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體莺琳,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年载慈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惭等。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡办铡,死狀恐怖辞做,靈堂內(nèi)的尸體忽然破棺而出琳要,到底是詐尸還是另有隱情,我是刑警寧澤秤茅,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布稚补,位于F島的核電站,受9級(jí)特大地震影響嫂伞,放射性物質(zhì)發(fā)生泄漏孔厉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一帖努、第九天 我趴在偏房一處隱蔽的房頂上張望撰豺。 院中可真熱鬧,春花似錦拼余、人聲如沸污桦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凡橱。三九已至,卻和暖如春亭姥,著一層夾襖步出監(jiān)牢的瞬間稼钩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來泰國打工达罗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坝撑,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓粮揉,卻偏偏與公主長得像巡李,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子扶认,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351