JS中的變量提升

js和其他語言一樣,都要經(jīng)歷編譯和執(zhí)行階段。而js在編譯階段的時(shí)候,會(huì)搜集所有的變量聲明并且提前聲明變量,而其他的語句都不會(huì)改變他們的順序,因此,在編譯階段的時(shí)候,第一步就已經(jīng)執(zhí)行了,而第二步則是在執(zhí)行階段執(zhí)行到該語句的時(shí)候才執(zhí)行

也就是說,在編譯的時(shí)候,頁面上所有的變量都已經(jīng)被聲明了,但是都還沒有賦值,即數(shù)據(jù)類型暫為undefined。

例1

a = 5
var a
console.log(a)

那么這里會(huì)打印出什么呢?按照正常的從上到下的邏輯思路,第2行的a并沒有被定義,所以第四行打印a時(shí)應(yīng)該會(huì)報(bào)錯(cuò)說 a is not defined,但是,注意注意,這里的a被提升了。

“變量提升會(huì)將當(dāng)前作用域的所有變量的聲明提升到程序的頂部”,意思就是說,雖然在第2行的a沒有用關(guān)鍵字 var 定義,但是編譯時(shí)會(huì)查找所有的var,把它們放到該作用域的最頂部,相當(dāng)于以下的代碼執(zhí)行過程:

var a
a = 5
console.log(a)

例2

console.log(a)
a = 5
var a

是不是跟例1很像?只不過把賦值語句跟打印語句調(diào)換了一下位置。那么現(xiàn)在第2行的執(zhí)行結(jié)果是打印出什么呢?結(jié)果是 undefined。回憶一下變量提升的操作,把所有的var都提到最頂部,在這里就是把 var a 放到最開頭,接下來就是console.log(a),很明顯,這里的a還沒被賦值,是在打印語句之后才被賦值,所以,已定義但未賦值的變量的數(shù)據(jù)類型是undefined,所以打印結(jié)果是undefined。
理解到簡單的定義之后,就要思考一下相對(duì)比較復(fù)雜的變量提升了,我們結(jié)合函數(shù)來看看

第一種情況:函數(shù)有參數(shù),且與函數(shù)內(nèi)部的變量同名

function show(a){
    console.log(a);//10
    var a=20
    console.log(a);//20
    }
show(10)

開始學(xué)函數(shù)參數(shù)的時(shí)候,老師跟我們說,形參就相當(dāng)于是在函數(shù)內(nèi)部定義了一個(gè)變量,就是var 了一個(gè)變量;然后實(shí)參傳進(jìn)來就相當(dāng)于是給這個(gè)變量賦了值。接下來我們就可以沿著這個(gè)思路去分析。還有一點(diǎn):參數(shù)名和變量名同名,參數(shù)優(yōu)先級(jí)高于變量提升

因?yàn)閰?shù)變量提升優(yōu)先級(jí)高,所以在函數(shù)被調(diào)用后,參數(shù)傳值的執(zhí)行順序是在變量賦值之前的,即var a之后,是 a = 10(傳參),相當(dāng)于以下的代碼執(zhí)行順序:

function show(){
      var a
      a = 10
      console.log(a);//10    
      a = 20
      console.log(a);//20
}    
show()

第二種情況:函數(shù)沒有參數(shù),函數(shù)內(nèi)部的變量未以關(guān)鍵字 var 定義

function show(){
      a=10    // 不加var,此處的a就變成了全局變量
      console.log(a); //10
}
show()
console.log(a); //10

注意看第2行的a,它前面沒有 var 關(guān)鍵字,此時(shí),當(dāng)show函數(shù)被調(diào)用后,a就被添加到了window對(duì)象中,成為了一個(gè)全局變量,全局變量在script的任何地方都能被訪問,所以最后一行,在函數(shù)外部也能訪問 a,結(jié)果打印10(如果前面沒有調(diào)用show,即show(),那么a就沒被創(chuàng)建,即未定義)

第三種情況:函數(shù) 有/無 參數(shù),函數(shù)內(nèi)部的變量以 var 定義
此時(shí)的var 后面的變量就是一個(gè)局部變量,也就是說,這個(gè)變量只能在其作用于內(nèi)部被訪問。

function show(){
    var a=10
    console.log(a); //10
}
show()
console.log(a);// a is not defined 局部變量 不能在外邊被訪問

第四種情況:函數(shù)外部的全局變量跟函數(shù)內(nèi)部的局部變量同名

var tt = 'aa';
function test(){
    alert(tt);  //先變量提升,tt在全局和函數(shù)內(nèi)部都有,優(yōu)先考慮局部變量提升,所以var tt提到alert上面,即undefined
    var tt = 'dd';  //局部變量賦值,所以tt現(xiàn)在有值了,為"dd""
    alert(tt);  //彈出dd
}
test();

當(dāng)局部變量和全局變量都有提升時(shí),優(yōu)先考慮局部變量提升。

第五種情況:函數(shù)提升跟變量提升的變量重名

函數(shù)也是一個(gè)變量,可以用函數(shù)聲明的方式定義,也可以用函數(shù)表達(dá)式的方式定義,所以也存在函數(shù)提升。

當(dāng)有多個(gè)同名變量聲明的時(shí)候,函數(shù)聲明會(huì)覆蓋其他的聲明。如果有多個(gè)函數(shù)聲明,則是由最后的一個(gè)函數(shù)聲明覆蓋之前所有的聲明。

舉個(gè)例子來解釋一下:

fn()

function fn() {
  console.log('1')
  var fn = 40
  console.log(fn)
}

function fn() {
  console.log('2')  //2
  var fn = 10
  console.log(fn) //10
}
var fn = function(){
  console.log('3')
}
console.log(fn) //function(){console.log('3')}

在這里,第一行就先調(diào)用了函數(shù)fn。因?yàn)槌霈F(xiàn)變量重名的情況時(shí),函數(shù)聲明高于所有變量聲明,即函數(shù)聲明最先實(shí)現(xiàn),那么第3行和第9行的function fn就最先被聲明,又因?yàn)?strong>如果有多個(gè)函數(shù)聲明,則是由最后的一個(gè)函數(shù)聲明覆蓋之前所有的聲明,所以第9行的fn會(huì)覆蓋第3行的fn,相當(dāng)于fn這個(gè)函數(shù)的函數(shù)主題就是第9行下邊的內(nèi)容。緊接著就是fn被調(diào)用(第一行),依次執(zhí)行,輸出結(jié)果打印2,10(局部變量)。然后執(zhí)行到第14行的時(shí)候,因?yàn)樽兞刻嵘?,var fn 已經(jīng)提到頂部去了,所以這里只剩下賦值語句 fn = function{console.log('3')},相當(dāng)于給fn賦了一個(gè)新的值,就跟 var a = 1; a = 5 是一個(gè)道理。此時(shí)打印fn,則輸出的是這個(gè)新的函數(shù)內(nèi)容 function{console.log('3')}。那么,如果在這后面再調(diào)用一次fn,會(huì)輸出什么呢?結(jié)果是3。因?yàn)榇藭r(shí)fn就是一個(gè)新的函數(shù)了,他的主體部分就是打印字符3。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. 什么是變量提升? 當(dāng)棧內(nèi)存(作用域)形成, JS代碼自上而下執(zhí)行之前,瀏覽器首先會(huì)把所有帶var/funct...
    _hider閱讀 3,278評(píng)論 0 2
  • 像變量提升和函數(shù)提升這種偏學(xué)院派的問題在面試中出現(xiàn)的概率很高,在實(shí)際開發(fā)中也會(huì)影響到編程的效率。 前段時(shí)間在網(wǎng)上做...
    時(shí)和歲稔閱讀 1,186評(píng)論 1 7
  • 1.提升的概念 簡單說就是在js代碼執(zhí)行前引擎會(huì)先進(jìn)行預(yù)編譯,預(yù)編譯期間會(huì)將變量聲明與函數(shù)聲明提升至其對(duì)應(yīng)作用域的...
    dream_Q閱讀 681評(píng)論 0 0
  • 概念 從概念的字面意義上說,“變量提升”意味著變量和函數(shù)的聲明會(huì)在物理層面移動(dòng)到代碼的最前面,但這么說并不準(zhǔn)確。實(shí)...
    Mokingc閱讀 203評(píng)論 0 0
  • 沒錯(cuò),經(jīng)典變量提升,經(jīng)典炒冷飯,我將其稱之為典中典。 什么是提升? 引擎會(huì)在解釋 JavaScript 代碼之前首...
    AmingYo閱讀 314評(píng)論 0 0

友情鏈接更多精彩內(nèi)容