1. 程式人生 > 程式設計 >淺談JavaScript 宣告提升

淺談JavaScript 宣告提升

1 引例及基本原理

在學習JavaScript宣告提升之前,我們先看下面這個例子:

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

執行結果會是什麼?你可能會有以下的猜測:

1.報錯ReferenceError: a is not defined;

2.列印2;

3.列印undefined。

正確的結果是第三種,列印undefined。

下面讓我們來看看具體的原因。其實,對於var a=2;這條語句,JavaScript會將其視為兩個宣告:

  1. 定義宣告var a,會在編譯階段進行;
  2. 賦值宣告a=2,會留在原地等待執行階段進行。

而所謂的宣告提升:就是JavaScript會把var變數宣告和函式宣告都會被提升到各自作用域的頂部,而賦值操作並不會被提升。

因此,上面的例子實際是按照這樣的流程來處理:

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

我們還需要知道,不僅僅是var變數宣告會提升,函式宣告同樣也會提升,現在來看下面這個例子

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

這個例子的執行結果為:列印undefined。這段程式碼實際上會被理解為為下面的形式:

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

2 關於宣告提升的常見問題

2.1 函式表示式

先看一個函式表示式的例子:

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

上面程式碼的執行結果為:列印undefined。實際上,變數識別符號foo被提升了,但它的賦值操作並沒有被提升,我們可以理解為下面的形式:

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

結論:函式宣告會被提升,但函式表示式不會被提升。

2.2 宣告的優先順序

如果在同一個作用域內,存在同名的函式宣告和var變數宣告,那麼會發生什麼樣的情況呢?我們同樣再來看一個例子:

function a(){}
var a;
console.log(a);
var a;
function a(){}
console.log(a);

上面的兩種寫法,執行結果均為列印a(){}。也就是說,如果在同一個作用域內,存在同名的函式宣告和var變數宣告,則函式宣告的優先順序更高。

還有一種情況:如果同一個作用域內,存在多個同名的函式宣告。這種情況下,後面宣告的會覆蓋前面宣告的。

3 練習題

3.1 第一題

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

答案:列印1

解析:提升後的順序如下

var getName;//與函式宣告同名,故失效
function getName() {
 console.log(2);
}
getName = function() {//賦值
 console.log(1);
};
getName();

3.2 第二題

var a = 1;
function b(){
 a = 10;
 return;
 function a(){
  console.log(a);
 } 
}
b();
console.log(a); 

答案:列印1

解析:首先,我們需要梳理清楚宣告的提升。
本題有幾個關鍵點,我們需要明白:

函式b內的a函式雖然在return之後,但它並沒有失效,它會發生宣告提升,從而提升到b函式作用域的頂部。

很多童鞋(比如我TAT)可能會錯誤地認為這題的答案是10,認為我們在最後呼叫了b函式,修改了全域性變數a。實際上,由於函式a發生了宣告提升,導致在函式b內“遮蔽”了全域性作用域中的變數a,因此,a=10;其實是將函式a重新賦值。為了進一步測驗,大家可以把a函式註釋掉,會發現此時的答案就變成了10。

注:本題還涉及到了閉包的相關知識,這一題詳細的解析請見參考資料[2],講得非常詳細。

var a;//全域性變數a發生了宣告提升
function b(){
 function a(){//函式a發生宣告提升
   console.log(a);
  }
 a = 10;//因為函式a離它最近,因此賦值給函式a
 return; 
}
a = 1;//賦值給了全域性變數a
b();
console.log(a); 

4 參考資料

[1] 《你不知道的JavaScript》

[2] js中變數名與函式名重名的問題,Charles_Tian

[3] 函式宣告與變數宣告的提升機制優先順序問題,一個菜鳥的奮鬥史

以上就是淺談JavaScript 宣告提升的詳細內容,更多關於JavaScript 宣告提升的資料請關注我們其它相關文章!