您好,登錄后才能下訂單哦!
變量提升
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,證明這個變量還是有的,只不過它并不是一個函數,這情況和用函數表達式差不多。
總結
好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。