函數(shù)聲明提升與變量聲明提升

最近在吃飯的時(shí)候看到一道關(guān)于函數(shù)聲明提升的問題

var a = 1;

function b() {
    a = 10;
    return;

    function a() {
    }
}

b();
console.log(a)  //1

很多人在看第一眼的時(shí)候會(huì)認(rèn)為結(jié)果為10,我作為一個(gè)小白第一反應(yīng)也是認(rèn)為函數(shù)內(nèi)部的a是全局變量,所以在執(zhí)行b后a的值變?yōu)?0,之后再看了后面的分析后才恍然大悟,在b函數(shù)執(zhí)行后a依然是1,于是琢磨這寫了人生中第一篇博客,寫的不好請(qǐng)見諒,若有技術(shù)問題,會(huì)在第一時(shí)間解決

1.變量聲明

使用var聲明的變量,如果在聲明時(shí)變量沒有賦值,系統(tǒng)則默認(rèn)賦值為undefined

2.沒有塊級(jí)作用域

在ES6的let,const出現(xiàn)之前,JavaScript是沒有塊級(jí)作用域的,也就是自己的執(zhí)行環(huán)境,在《JavaScript高級(jí)程序設(shè)計(jì)》中提到

if (true) {
    var color = "blue";
}
alert(color);  //"blue"

在JavaScript中,if語句中的變量聲明會(huì)將變量加到當(dāng)前的執(zhí)行環(huán)境(這里指的是全局環(huán)境)中相當(dāng)于以下代碼,而var聲明的變量是在JavaScript預(yù)編譯階段就執(zhí)行了的

//預(yù)編譯階段
var color;
//執(zhí)行階段
if (true) {
    color = "blue";
}
console.log(color);  //"blue"

還有一個(gè)非常經(jīng)典的問題

for (var i = 0; i < 10; i++) {
//這里做任意事情
}
alert(i);  //10

這里彈出i的值為10,可以理解為for循環(huán)開始的時(shí)候定義了i變量,然后在for循環(huán)完成后,i變量依然存在于全局環(huán)境中,并且在alert(i)的時(shí)候for循環(huán)已經(jīng)結(jié)束,i的值等于10,所以alert(i)的結(jié)果就是10了

3.變量聲明提升

再來回到第一個(gè)例子,如果它的條件為false

if (false) {
    var color = "blue";
}
alert(color);  //undefined

經(jīng)過變量聲明提升后實(shí)質(zhì)與以下代碼是一樣的

//預(yù)編譯階段
var color;
//執(zhí)行階段
if (false) {
    color = "blue";
}
console.log(color);  //undefined

因?yàn)閏olor定義了,但是if的條件為false,所以只聲明了color變量卻沒有賦值,最后顯示undefined

JavaScript編譯器會(huì)把變量聲明看成兩個(gè)部分分別是聲明操作(var color)和賦值操作(color="blue")

聲明操作在編譯階段進(jìn)行冰垄,聲明操作會(huì)被提升到執(zhí)行環(huán)境的頂部球榆,值是undefined(表示未初始化)

賦值操作會(huì)被留在原地等待執(zhí)行階段

注釋:聲明提前是在JavaScript引擎的預(yù)編譯時(shí)進(jìn)行丈冬,是在代碼開始運(yùn)行之前。

4.函數(shù)聲明提升

函數(shù)的兩種創(chuàng)建方式

1. 函數(shù)聲明

2. 函數(shù)表達(dá)式

函數(shù)聲明:

function sum(num1, num2) {
    return num1 + num2;
}退腥;

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

sum(10, 10);  //20
function sum(num1, num2) {
    return num1 + num2;
};

JavaScript編譯器在預(yù)編譯階段把代碼編譯后其實(shí)是這樣的

var sum;
sum = function (num1, num2) {
    return num1 + num2;
}乘客;
sum(10, 10);  //20

函數(shù)聲明會(huì)把先聲明一個(gè)變量sum,同時(shí)把函數(shù)賦值給變量sum

函數(shù)表達(dá)式:

var sum = function (num1, num2) {
    return num1 + num2;
}

通過把匿名函數(shù)賦值給變量的定義函數(shù)的方法叫做函數(shù)表達(dá)式淀歇,而通過函數(shù)表達(dá)式創(chuàng)建的函數(shù)和函數(shù)聲明不一樣易核,函數(shù)表達(dá)式?jīng)]有函數(shù)聲明提升,只有定義了之后才能調(diào)用,上述代碼實(shí)質(zhì)上是這樣的

var sum;
sum = function (num1, num2) {
    return num1 + num2;
}

在函數(shù)表達(dá)式創(chuàng)建的函數(shù)之前執(zhí)行sum函數(shù)

sum(10, 10);//報(bào)錯(cuò) Uncaught TypeError: sum is not a function
var sum = function (num1, num2) {
    return num1 + num2;
}

因?yàn)橥ㄟ^函數(shù)表達(dá)式創(chuàng)建的函數(shù)沒有函數(shù)提升,所以執(zhí)行sum(10,10)時(shí)根本沒有創(chuàng)建函數(shù),但是沒有創(chuàng)建函數(shù)應(yīng)該會(huì)顯示undefined,為什么會(huì)報(bào)錯(cuò)呢,實(shí)質(zhì)上上述代碼是這樣的

//預(yù)編譯階段
var sum;
//執(zhí)行階段
sum(10, 10);
sum = function (num1, num2) {
    return num1 + num2;
};

可以把函數(shù)表達(dá)式看作2部分,第一部分聲明變量sum,第二部分給變量sum賦于這個(gè)匿名函數(shù),而通過var聲明的sum存在變量提升,在預(yù)編譯階段會(huì)提升到執(zhí)行環(huán)境頂部,然后在執(zhí)行sum(10,10)就會(huì)報(bào)錯(cuò),提示sum不是一個(gè)函數(shù),undefined當(dāng)然不是一個(gè)函數(shù)啦,第三行執(zhí)行完畢后,這時(shí)sum才指向了這個(gè)函數(shù)

函數(shù)聲明提升>形參>變量聲明提升

當(dāng)同時(shí)存在函數(shù)聲明和變量聲明時(shí),來看這個(gè)例子

getName();  //1
var getName = function () {
    console.log(2);
}

function getName() {
    console.log(1);
}

getName();  //2

當(dāng)存在函數(shù)聲明和變量聲明時(shí),函數(shù)聲明在前,變量聲明在后,所以上述代碼是這樣的

//預(yù)編譯階段
//使用函數(shù)聲明創(chuàng)建的函數(shù)函數(shù)聲明提升
var getName;
getName = function () {
    console.log(1);
};
//變量聲明提升,因?yàn)橹耙呀?jīng)聲明過getName,所以再次聲明var會(huì)被忽略
var getName;

//執(zhí)行階段
getName();  //1
getName = function () {
    console.log(2);
};
getName();  //2

再來看一道面試題

var a = 1;

function b() {
    a = 10;
    return;

    function a() {
    }
}

b();
console.log(a);  //1

在b函數(shù)內(nèi)部,因?yàn)榇嬖诤瘮?shù)變量聲明提升,導(dǎo)致return后面的function a () {}被提升到了b函數(shù)內(nèi)部的頂部,等同于在b函數(shù)內(nèi)部聲明了局部變量a(與函數(shù)外部的全局變量a不同),并且給變量a賦值給一個(gè)匿名函數(shù),最后再給局部變量a賦值為10,最后return退出函數(shù),局部變量a在b函數(shù)執(zhí)行完后被銷毀,console.log(a)打印變量a的時(shí)候會(huì)搜索變量a浪默,最后只在最后的全局變量中發(fā)現(xiàn)了a牡直,隨即打印了a的值,即數(shù)字1(第一行聲明的變量a)

var a = 1;

function b() {
    var a;
    a = function () {
    };
    a = 10;
    return;
}

b();
console.log(a);  //1
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末纳决,一起剝皮案震驚了整個(gè)濱河市碰逸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌岳链,老刑警劉巖花竞,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異掸哑,居然都是意外死亡约急,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門苗分,熙熙樓的掌柜王于貴愁眉苦臉地迎上來厌蔽,“玉大人,你說我怎么就攤上這事摔癣∨” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵择浊,是天一觀的道長戴卜。 經(jīng)常有香客問我,道長琢岩,這世上最難降的妖魔是什么投剥? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮担孔,結(jié)果婚禮上江锨,老公的妹妹穿的比我還像新娘吃警。我一直安慰自己,他們只是感情好啄育,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布酌心。 她就那樣靜靜地躺著,像睡著了一般挑豌。 火紅的嫁衣襯著肌膚如雪安券。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天浮毯,我揣著相機(jī)與錄音完疫,去河邊找鬼。 笑死债蓝,一個(gè)胖子當(dāng)著我的面吹牛壳鹤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播饰迹,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼芳誓,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了啊鸭?” 一聲冷哼從身側(cè)響起锹淌,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赠制,沒想到半個(gè)月后赂摆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡钟些,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年烟号,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片政恍。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡汪拥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出篙耗,到底是詐尸還是另有隱情迫筑,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布宗弯,位于F島的核電站脯燃,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蒙保。R本人自食惡果不足惜曲伊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧坟募,春花似錦、人聲如沸邑狸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽单雾。三九已至赚哗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間硅堆,已是汗流浹背屿储。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留渐逃,地道東北人够掠。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像茄菊,于是被迫代替她去往敵國和親疯潭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353