前言:做爲解釋性語言的JS,在執行前會先進行預編譯。理解了預編譯,JS中的變量提高就能夠更快的搞懂啦!javascript
在講解預編譯前,先講解個知識點。敲黑板啦!小夥伴們不要光看,本身打打代碼才知道。java
window
全部。以下所示,即window.a = 10
。這個
window
究竟是什麼,其實它就是一個全局對象,提供了一個全局做用域。在全局做用域聲明變量,就是爲全局對象添加屬性。即在window對象中添加了一個屬性a,其值爲10。bash
<script type="text/javascript">
a = 10;
console.log(a);//訪問這個a實際上就是訪問window.a
<script>
複製代碼
爲了更好地理解,再來看一下下面代碼。
window.a和window.b
會輸出什麼呢?
<script type="text/javascript">
function test() {
var a = b = 123;
}
test();
<script>
複製代碼
步驟:
window
的一個屬性,因此能夠經過window.變量名訪問
。window
的屬性。<script type="text/javascript">
var b = 20;
console.log(b);
<script>
複製代碼
看一段代碼函數
undefined
,那麼undefined
是什麼意思呢?是var
聲明瞭變量可是未對它進行初始化。因此先讓這個變量初始化爲undefined
,也就是先讓b=undefined
直到真正賦值階段時纔是20。Uncaught ReferenceError: Cannot access 'a' before initialization
。翻譯過來的意思就是沒法在初始化以前訪問a。<script type="text/javascript">
//var
console.log(b);//undefined
var b = 20;
//let
console.log(a);//Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 10;
<script>
複製代碼
爲何
var
和let
二者不同呢?先來說講var
吧ui
var b = 20;
包括兩個步驟:<script type="text/javascript">
var b;//該聲明提高了,提高到做用域的頂部。
console.log(b);//undefined
b = 20;
<script>
複製代碼
var的提高實際上是建立和初始化都提高了。也許你又會問那爲何初始化的值是undefined。這和執行前發生的預編譯有關。spa
先看下面的代碼到底輸出什麼?既有函數又有變量,並且還同名,那變量的聲明提高和函數提高到底誰的優先級高呢?想必是很懵逼吧,不要緊,跟着我一塊兒來一步一步理解下。翻譯
function test(a)
{
console.log(a);
var a = 123;
console.log(a);
function a() {}
console.log(a);
var b = function () {}
console.log(b);
function d() {}
}
test(1);
複製代碼
AO{}
複製代碼
AO{
形參或變量聲明:undefined
}
也就是
AO{
a:undefined,//這裏形參function test(a)和變量var a都是,寫一次就行了
b:undefined
}
複製代碼
AO{
形參或變量聲明:實參
}
也就是
AO{
a:1,
b:undefined
}
複製代碼
AO{
形參或變量聲明:函數體
}
也就是
AO{
a:function a() {},//函數聲明
b:undefined,
//注意了 var b = function () {}這個不是函數聲明,是函數表達式,因此b的值仍是undefined
d:function d() {}//函數聲明
}
複製代碼
注意:要打印的值都從預編譯後的AO對象中取值code
function test(a)
{
//1.輸出function a() {}
console.log(a);
/*2. 預編譯時已經變量提高了,可是賦值尚未操做。因此此時AO對象中a的值改變爲123
AO{
a:123,
b:undefined,
d:function d() {}
}
*/
a = 123;
//3.輸出:123
console.log(a);
function a() {}
//4.輸出123
console.log(a);
/*5.改變AO對象中b的值
AO{
a:123,
b:function () {},
d:function d() {}
}
*/
var b = function () {}
//6.輸出function () {}
console.log(b);
function d() {}
}
複製代碼
實際輸出結果和分析的同樣。棒棒噠!cdn
理解了預編譯後,想必var
的變量提高弄明白了吧!var提高指的是建立和初始化都被提高了。因此下面代碼輸出的結果纔是undefined對象
console.log(a);
var a = 20;
複製代碼
console.log(a);//Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 10;
複製代碼
對於上面的結果也許你會說:那let不就沒有提高。這就錯了,其實它是有提高的,只不過提高的只有建立過程,初始化時沒有提高的。看碼
let a = 1;
{
console.log(a);
let a = 2;
}
複製代碼
若是let不存在提高,那麼應該輸出1。可是卻報錯 Uncaught ReferenceError: Cannot access 'a' before initialization。這就說明let存在提高。只是被存在「暫存死區」中。只有當初始化後才能被引用。
var
:【建立】和【初始化】都被提高function
:總體提高,也就是【建立】【初始化】【賦值】都被提高let
:【建立】過程提高,但初始化沒有提高。