隨筆記錄--JS變量提升

1. JS中的作用域

在js 中有兩種作用域

  • 全局作用域
  • 函數(shù)作用域
    在es6之前,js中沒有塊級作用域毙驯。
    這里解釋一下什么是塊級作用域
var i = 0;
if(true) {
    a = "我是linK哥";
}
console.log(a);

上面的代碼稽坤,i的作用域是全局作用域滨攻,a是屬于if的{}里面的,但是由于js中沒有塊級饶唤,所以這里的a的作用域仍然屬于全局作用域徐伐。

2.什么是變量提升

先來看下面的代碼:

console.log(a);
var a = 12;

從上面的代碼中可以看出,先執(zhí)行a募狂,再定義a = 12,但是執(zhí)行第一行console.log(a)的時候并沒有報錯办素,而是輸出undefined,這說明在執(zhí)行console.log(a);之前祸穷,瀏覽器中已經(jīng)聲明了a性穿。

當(dāng)棧內(nèi)存(作用域),JS代碼自上而下執(zhí)行之前雷滚,瀏覽器首先會把“var.function"關(guān)鍵詞的變量進(jìn)行提升"聲明"或者"定義"需曾,這種預(yù)先處理機制稱之為"變量提升"。
=>聲明(declare):var a (默認(rèn)值undefined)
=>定義(defined):a=12 (定義其實就是賦值操作)

變量提升只發(fā)生在當(dāng)前作用域(例如:開始加載頁面的時候只對全局作用域下的進(jìn)行提升祈远,因為此時函數(shù)中存儲的都是字符串而已)
在全局作用域下聲明的函數(shù)或者變量是“全局變量”呆万,同理,在私有作用域下聲明的變量是“私有變量” [帶VAR/FUNCTION的才是聲明]

通過下面這段代碼詳細(xì)解讀變量提升機制

var a = 12;
/*
 * 1.先聲明一個變量a车份,沒有賦值(默認(rèn)值是undefined)
 * 2.在當(dāng)前作用域中開辟一個位置存儲12這個值
 * 3.讓變量a和12關(guān)聯(lián)在一起(定義:賦值)
 */
var b = a;
b = 13;
console.log(a);

//編寫一個函數(shù)實現(xiàn)任意數(shù)求和
function sum () {
    var total = 0;
    for(var i=0;i<arguments.length;i++) {
        var item = parseFloat(arguments[i]);  //因為argument存儲的是字符串谋减,需要轉(zhuǎn)成數(shù)字
        // !isNaN(item) ? total += item : null;
        if( !isNaN(item)) {
            total += item;
        }
    }
    return total;
}
console.log(sum(10,12,15,41,10));


瀏覽器在加載頁面的時候,首先開啟一個window全局棧內(nèi)存扫沼,會把“var/function"關(guān)鍵詞的變量進(jìn)行提升"聲明"或者"定義"出爹,從上面的代碼中可以知道在變量提升階段會聲明變量a,b,還有sum,由于sum是屬于函數(shù)對象缎除,因此它的聲明會把函數(shù)體以字符串的形式放在堆內(nèi)存中以政,假設(shè)這塊堆內(nèi)存的地址是AAAFFF111,則sum就指向AAAFFF111這塊堆內(nèi)存空間伴找,接著js代碼進(jìn)行自上而下執(zhí)行盈蛮,當(dāng)執(zhí)行到function sum ()的時候會跳過函數(shù)創(chuàng)建的代碼,因為在變量提升階段函數(shù)已經(jīng)聲明了技矮。最后執(zhí)行sum()函數(shù)抖誉,這里會形成一個私有作用域殊轴,私有作用域形成后,也不是立即執(zhí)行代碼袒炉,一樣先進(jìn)行變量提升(變量提升錢旁理,先進(jìn)行形參賦值),然后再是js代碼自上而下地執(zhí)行我磁。

注意:在ES3/ES5語法規(guī)范中孽文,只有全局作用域和函數(shù)執(zhí)行的私有作用域(棧內(nèi)存),其中它大括號不會形成棧內(nèi)存夺艰。

3. 帶var 和不帶 var的區(qū)別

在全局作用域下聲明一個變量芋哭,也相當(dāng)于給window全局對象設(shè)置了一個屬性,全局變量和window屬性存在“映射機制”郁副,變量的值就是屬性的值(私有作用域中聲明的私有變量和window沒啥關(guān)系)

3.1 帶var

console.log(a);  //undefined  由于變量替身的影響减牺,所以輸出的是undefined

console.log(window.a);  //undefined
// console.log('a' in window);    //true
// in 檢測屬性是否隸屬于這個對象

var a = 12;
console.log(a);  //12  全局變量
console.log(window.a);  //12   window屬性的a

帶var是可以進(jìn)行預(yù)解釋的(變量提升)所以賦值前面執(zhí)行是不會報錯的。在變量提升階段存谎,在全局作用域中聲明了一個變量a拔疚,此時已經(jīng)把a當(dāng)做一個屬性賦值給window了,只是還沒給它賦值a既荚。
下面通過var定義了全局變量var a = 12;,這時候window全局對象也設(shè)置了一個屬性a=12;稚失。所以打印輸出的結(jié)果都是12。但是這時候如果在var a = 12;之前打印window.a恰聘,發(fā)現(xiàn)輸出的是undefined墩虹,這說明這時候a并不是window中的屬性,我們也可以通過console.log('a' in window);來判斷憨琳。

3.2 不帶var

// console.log(a);  // error Uncaught ReferenceError: a is not defined

console.log(window.a);  //undefined
console.log('a' in window);  // false  說明a不是window中的屬性

a = 12;   //這里并不是賦值诫钓,只是window.a = 12 的簡寫 (本質(zhì)是window下的屬性,不是變量)
console.log(a);  //12
console.log(window.a);  //12 

不帶var的是不能進(jìn)行預(yù)解釋的(變量提升)篙螟,在前面執(zhí)行會報錯(ReferenceError)菌湃。
a=12;不帶var并不是賦值,而是相當(dāng)于給window添加了一個叫做a的屬性遍略,其屬性值為12惧所。在a=12;之前a是不屬于window的屬性的,可以通過console.log('a' in window);進(jìn)行判斷绪杏。

特別注意

var a = 12,
    b = 13; //遮掩寫b 是帶var 的

var a = b = 12;  //這樣寫b是不帶var的
// 相當(dāng)于:
// var a = 12;
// b = 12;

3.3 私有作用域中的var

console.log(a,b);  //undefined undefined
var a = 12,
    b = 12;

function fn() {
    console.log(a,b);  //undefined 12
    var a = b = 13;  
    //相當(dāng)于: var a = 13;   b= 13;

    console.log(a,b);  //13 13
}
fn();
console.log(a,b); //12 13

私有作用域中帶var和不帶var也有區(qū)別:

  • 帶var在私有作用域變量提升階段下愈,都聲明為私有變量,和外界沒有任何關(guān)系
  • 不帶var不是私有變量蕾久,比如fn()里面的b势似,它會向它的上級作用域中查找,看是否為上級的變量,如果不是履因,就繼續(xù)查找障簿,一直到window位置(這種查找機制叫做:“作用域鏈”),也就是我們私有作用域操作的非私有變量栅迄,是可以直接操作外界的站故。

但是,如果找到window都沒有找不到呢毅舆?

function fn() {
    /**
     * 沒有變量提升
     */
    //但是如果在這輸出b 就會報錯
    // console.log(b); //  ReferenceError: b is not defined
    b = 13;

    // 觀察
    console.log('b' in window); //true
    //在作用域鏈查找的過程中西篓,如果window也沒有這個變量,相當(dāng)于window設(shè)置了一個屬性b  (window.b = 13)
    console.log(b); //13
}
fn();
console.log(b);  //13 所以這里輸出是window.b 

通過上面代碼可知憋活,如果window也找不到岂津,可以分為兩種情況:

  • 第一種情況:我們獲取的值console.log(b);報錯了,ReferenceError余掖。
  • 第二種情況:相當(dāng)于給window添加了一個屬性b,其屬性值為13;

3.4 總結(jié)

  • 在全局作用域中:帶var可以進(jìn)行預(yù)解釋礁鲁,所以在賦值前面執(zhí)行不會報錯盐欺,不帶var不進(jìn)行預(yù)解釋,在前面執(zhí)行會報錯(ReferenceError)仅醇。
  • a=12;相當(dāng)于給window添加一個叫做a的屬性名冗美,其屬性值是12
    var a = 12;相當(dāng)給全局作用域添加一個全局變量a,但是不僅如此析二,它也相當(dāng)于給window添加一個屬性名粉洼。
  • 私有作用域中出現(xiàn)的一個變量不是私有的,則往上級作用域進(jìn)行查找叶摄,上級沒有属韧,則繼續(xù)向上查找,一直找到window為止蛤吓。如果window也沒有宵喂,第一種是獲取值的時候會報錯,第二種是給window增加一個屬性会傲。

注意:在當(dāng)前作用域下锅棕,不管條件是否成立都要進(jìn)行變量提升
=>帶VAR的還是只聲明
=>帶function的在老版本瀏覽器渲染機制下,聲明和定義都處理淌山,但是為了迎合ES6中的塊級作用域裸燎,新版瀏覽器對于函數(shù)(在條件判斷中的函數(shù)),不管條件是否成立泼疑,都只是先聲明德绿,沒有定義,類似于VAR

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市脆炎,隨后出現(xiàn)的幾起案子梅猿,更是在濱河造成了極大的恐慌,老刑警劉巖秒裕,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件袱蚓,死亡現(xiàn)場離奇詭異,居然都是意外死亡几蜻,警方通過查閱死者的電腦和手機喇潘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來梭稚,“玉大人颖低,你說我怎么就攤上這事』】荆” “怎么了忱屑?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長暇昂。 經(jīng)常有香客問我莺戒,道長,這世上最難降的妖魔是什么急波? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任从铲,我火速辦了婚禮,結(jié)果婚禮上澄暮,老公的妹妹穿的比我還像新娘名段。我一直安慰自己,他們只是感情好泣懊,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布伸辟。 她就那樣靜靜地躺著,像睡著了一般馍刮。 火紅的嫁衣襯著肌膚如雪自娩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天渠退,我揣著相機與錄音忙迁,去河邊找鬼。 笑死碎乃,一個胖子當(dāng)著我的面吹牛姊扔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播梅誓,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼恰梢,長吁一口氣:“原來是場噩夢啊……” “哼佛南!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嵌言,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤嗅回,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后摧茴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绵载,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年苛白,在試婚紗的時候發(fā)現(xiàn)自己被綠了娃豹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡购裙,死狀恐怖懂版,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情躏率,我是刑警寧澤躯畴,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站薇芝,受9級特大地震影響蓬抄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜恩掷,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一倡鲸、第九天 我趴在偏房一處隱蔽的房頂上張望供嚎。 院中可真熱鬧黄娘,春花似錦、人聲如沸克滴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽劝赔。三九已至誓焦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間着帽,已是汗流浹背杂伟。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留仍翰,地道東北人赫粥。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像予借,于是被迫代替她去往敵國和親越平。 傳聞我的和親對象是個殘疾皇子频蛔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355