首頁  >  文章  >  web前端  >  詳細介紹js中的變數提升機制

詳細介紹js中的變數提升機制

王林
王林轉載
2020-04-24 09:24:182087瀏覽

詳細介紹js中的變數提升機制

變數提升

JavaScript的變數提升有兩種,用var宣告的變數以及用function宣告的變數。

用var宣告的變數

我們先來看下面這段程式碼,a的值是多少

程式碼1

console.log(a);

var a;

。依照以往程式語言的思路來看,程式碼自上而下運行,按這種思路,會報錯,因為執行到第2行時,變數a還沒有定義,所以會報錯a is not defined

然而事實上答案是undefined

好,抱著疑惑,我們看下面的程式碼

var a;
console.log(a);

我們發現,這兩段程式碼是一樣的,那麼又有一個新的問題,是不是有沒有var a都無所謂,它的答案始終是undefined,才造成了以為變數會提升的錯覺,於是我寫了程式碼3

程式碼3

console.log(a);

好,它終於報錯了,所以這證明了javaScript程式碼並不是自上而下執行的,至少從表面看上面是這樣的。

於是我們再看程式碼4

程式碼4

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

因為變數提升嘛,所以答案是2,然而事實上,它還是undefined,why?

這時候我們有請編譯器這位負責文法分析及程式碼產生等髒活累活的大佬。

編譯器在看到var a = 2;,它會將其看做兩個聲明,var a;和a = 2,第一個聲明在編譯階段進行,第二個聲明會被原地等待執行階段。

也就是說上面程式碼,會變成下面的這段程式碼

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

所以最後會是undefined

好,我在囉嗦一下,看這段程式碼5

程式碼5

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

我想大家應該已經知道這段程式碼執行時的真正順序及其答案了,沒錯,答案是2,但我想說的是把第2行給註解掉,答案依然是2,但這個和變數提升沒啥關係了,是嚴格模式與非嚴格模式的鍋,在非嚴格模式下允許開發者可以不使用聲明變數的關鍵字,但在嚴格模式下是不可以的,它會報錯的。

用function宣告的變數

與var一樣,function宣告的變數依然會提升。

log(5);

function log(mes){
  console.log(mes)
}

按照先前的變數提升的理解,這段程式碼的真正順序是這樣的,

function log(mes){
  console.log(mes)
}

log(5);

很好,很正確,那麼再看下一段程式碼

log(5);

var log = function(mes){
  console.log(mes)
}

它報錯了,log is not a function,從這裡我們可以看出,這種函數表達式是不會被提升的,只有函數宣告才會被提升,試著在最前面新增一行程式碼console.log (log),會先輸出undefined。

所以這裡的真正順序是

var log;
log(); //这时候只是声明了log这个变量,并不是函数,却用函数的方法调用它,所以会报错,说这不是一个函数。
log = function(mes){
  console.log(mes)
}

在function裡用var宣告變數

我們雖然知道,var宣告的變數會提升,但不知道會提升到哪個程度。

在此之前來看一段程式碼

var a = 4;

function foo(){
  var a = 5;
  console.log(a);

}
foo();

console.log(a)

答案是5,4,先輸出5,再輸出4。

用var宣告的變數是有函數作用域的,所以foo裡的a和foo外面的a沒有任何關係,這種情況正是我想要的。

再改下程式碼

function foo(){
  a = 5
  console.log(a);
  var a;
}
foo();

console.log(a)

答案是5,a is not defined

第4行程式碼輸出5,第9行報錯。

這種情況就是變數提升只會提升到變數所在的 作用域的頂部,不會提升到父級作用域。

因此可以得出一個結論:變數提升只會將變數提升到自己所在的作用域的頂部

函數優先

既然用var和function的變數都有提升的功能,那如果同一個變數用這兩種都宣告會怎樣,好吧,看標題就知道了,函數優先。

具體看下程式碼

foo();

var foo;

function foo(){
  console.log(1)
}

foo = function(){
  console.log(2)
}

答案是1

這段程式碼其實這樣子的

function foo(){
  console.log(1)
}

foo();// 1

foo = function(){
  console.log(2)
}

仔細一看,var foo;沒了,沒錯,它被引擎忽略了,認為重複聲明所以把它拋棄了。

好,既然var宣告的變數比不了函數聲明,那就用函數聲明,多次聲明同變數。

foo()
function foo(){
  console.log(1);
}
foo()
function foo(){
  console.log(2);
}
foo()
function foo(){
  console.log(3);
}

foo()

foo宣告了三次,呼叫了四次,每次呼叫的結果都是3,所以最後的函數宣告會覆寫先前的函數宣告

但是var還想掙扎一下,覺得還是有必要證明自己的存在感的。

foo()
function foo(){
  console.log(1);
}
var foo;
foo()
foo = function(){
  console.log(2);
}
foo()
function foo(){
  console.log(3);
}

foo()

仔細看,中間那部分程式碼改了,依序輸出3,3,2,2

雖然var foo被忽略了,但下面的函數還是有用的,這段程式碼可以看成是這樣的

function foo(){
  console.log(3);
}

foo();//3
foo();//3
foo = function(){
  console.log(2);
}
foo();//2
foo();//2

在普通區塊內部宣告函數##​​

#之前是在作用域宣告函數,現在來區塊裡面宣告函數##​​#
function foo(){

  console.log(b); // undefined
  b(); //TypeError: b is not a function

  var a = true;

  if(a){
    function b(){
      console.log(2)
    }
    //下面这段代码和上面的结果一样
    // var b = function(){
 //      console.log(2)
 //    }
  }
  //b() --> 这里会被执行

}

foo()

從上面看上去,b是undefined,證明這個變數還是有的,只不過它並不是一個函數,這情況和用函數表達式差不多。

總結


1、提升分為函數宣告提升和變數宣告提升

2、宣告變數用var,宣告函數用function

3、變數提升會將變數提升到自己所在作用域的頂部

4、函數表達式不存在提升的機制

5、函數宣告和變數宣告同時宣告同一個標識符時,函數宣告優先

6、多個函數宣告同一個標識符時,最後一個宣告會覆寫先前的宣告

推薦教學:js教學

#

以上是詳細介紹js中的變數提升機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:jb51.net。如有侵權,請聯絡admin@php.cn刪除