深感與C語言及Java有很大的不同,
如果不是一開始就學JavaScript的人非常可能會把以前的觀念代入而遭遇匪夷所思的錯誤,
所以特地在此做個紀錄。
在JavaScript中,有兩個跟C語言及Java非常不同的特性,
- 變量的作用域不為塊級作用域(block-level scope),而且支持函數作用域(function-level scope)。
- 在作用域裡會有變量聲明提昇的現象。
下面做個說明:
1.變量的作用域不為塊級作用域(block-level scope),而且支持函數作用域(function-level scope)在C語言及Java中,只要在括弧( "()" 及 "{}") 中宣告的變數都屬於區域中的區域變數,例如以下程式碼:
int x = 1; if (true) { int x = 2; println(x); //2 } println(x); //1
很顯然地應該輸出為 2和1 ,因為大括弧{}中的int x=2;跟外面的int x=1 無關,兩次println(x)的x是不一樣的。
但是在JavaScript中,變數不是使用塊級作用域的,而是函數作用域的,例如以下的程式碼:
var x = 1; if (true) { var x = 2; alert(x); //2 } alert(x); //2
結果會是兩次的alert(x)都會顯示2,這是因為在if的大括弧{}裡的var x=2; 的x就是 外層的var x=1;,兩個x並沒有被當成是不同的x,所以內外層的alert(x)的x都是一樣的x。
因為JavaScript支持函數作用域,所以如果用函數來圍往同名變數的宣告的話,就可以區分內外的同名變數,如以下程式碼:
var x = 1; function myFun(){ var x = 2; alert(x); //2 } myFun(); alert(x); / /1
就會先顯示2再顯示1,因為此時myFun()裡的x與外層的x是不同的x變數。
2.在作用域裡會有變量聲明提昇的現象
另外一個JavaScript中獨特的特性是變量聲明提昇,以下兩種宣告情形會變提昇至作用域的頂端,即先被執行:
一、以var宣告變數的動作。
二、函數的無等號宣告 (如: function myFun(){} 這種,其實就等於 var myFun = function(){})
例如以下程式碼:
function sum() { try{ alert(sum.arguments.length); //sum為undefined ,出錯 var sum = 0; alert(sum); }catch(error){ alert(error); } } sum(1,2);
會補捉到TypeError: Cannot read property 'arguments' of undefined的錯誤,這是因為變量聲明提昇的作用,在提昇之後,其實真正的程式碼執行狀況長得就像下面這樣:
function sum() { try{ var sum; //變數的宣告被提至作用域頂端 alert(sum.arguments.length); //sum為undefined ,出錯 sum = 0; alert(sum); }catch(error){ alert(error); } } sum(1,2);
此時就很容易看出Error發生的原因,因為在sum()中,先宣告了一個sum屬性但未賦予其值,是undefined的,所以在alert(sum.arguments.length)中的sum是undefined的,當然就沒有arguments等屬性了。
再看一個例子,現在使用function的非等號式宣告:
var x = 1; function myFun(){< x = 2; return; function x(){}; } myFun(); alert(x);
答案是輸出1,因為被變數聲明提昇後的程式碼長得像這樣:
var x = 1; function myFun(){ var x; x = 2; return; x = function){}; } myFun(); alert(x);
所以myFun()跟本沒有影響到外層的var x = 1的x而輸出原來的1了。
參考資料:
沒有留言 :
張貼留言