js變數以及其範圍詳解

來源:互聯網
上載者:User

一、變數的類型
  Javascript和Java、C這些語言不同,它是一種無類型、弱檢測的語言。它對變數的定義並不需要聲明變數類型,我們只要通過賦值的形式,可以將各種類型的資料賦值給同一個變數。例如:
複製代碼 代碼如下:
i=100;//Number類型
i="variable";//String類型
i={x:4};//Object類型
i=[1,2,3];//Array類型

  JS的這種特性雖然讓我們的編碼更加靈活,但也帶來了一個弊端,不利於Debug,編譯器的弱檢測讓我們維護冗長的代碼時相當痛苦。
二、變數的聲明
  JS中變數申明分顯式申明和隱式申明。
  var i=100;//顯式申明
  i=100;//隱式申明
  在函數中使用var關鍵字進行顯式申明的變數是做為局部變數,而沒有用var關鍵字,使用直接賦值方式聲明的是全域變數。  
  當我們使用訪問一個沒有聲明的變數時,JS會報錯。而當我們給一個沒有聲明的變數賦值時,JS不會報錯,相反它會認為我們是要隱式申明一個全域變數,這一點一定要注意。
三、全域變數和局部變數
  當JS解析器執行時,首先就會在執行環境裡構建一個全域對象,我們定義的全域屬性就是做為該對象的屬性讀取,在頂層代碼中我們使用this關鍵字和window對象都可以訪問到它。而函數體中的局部變數只在函數執行時產生的調用對象中存在,函數執行完畢時局部變數即刻銷毀。因此在程式設計中我們需要考慮如何合理聲明變數,這樣既減小了不必要的記憶體開銷,同時能很大程度地避免變數重複定義而覆蓋先前定義的變數所造成的Debug麻煩。
四、變數範圍
  任何程式語言中變數的範圍都是一個很關鍵的細節。JS中變數的範圍相對與JAVA、C這類語言顯得更自由,一個很大的特徵就是JS變數沒有塊級範圍,函數中的變數在整個函數都中有效,運行下面代碼:
複製代碼 代碼如下:
<SCRIPT LANGUAGE="JavaScript" type="text/javascript">
//定義一個輸出函數
function outPut(s){
document.writeln(s)
}
//全域變數
var i=0;
//定義外部函數
function outer(){
//訪問全域變數
outPut(i); // 0
//定義一個類部函數
function inner(){
//定義局部變數
var i = 1;
// i=1; 如果用隱式申明 那麼就覆蓋了全域變數i
outPut(i); //1
}
inner();
outPut(i); //0
}
outer();
</SCRIPT>

  輸出結果為0 1 0,從上面就可以證明JS如果用var在函數體中聲明變數,那麼此變數在且只在該函數體內有效,函數運行結束時,本地變數即可銷毀了。
  由於上面的這個JS特性,還有一個關鍵的問題需要注意。此前一直使用ActionScript,雖然它和JS都是基於ECMA標準的,但在這裡還是略有不同的。例如下面代碼:
複製代碼 代碼如下:
<SCRIPT LANGUAGE="JavaScript" type="text/javascript">
//定義一個輸出函數
function outPut(s){
document.writeln(s)
}
//全域變數
var i=0;
//定義外部函數
function outer(){
//訪問全域變數
outPut(i); // 0
//定義一個類部函數
function inner(){
outPut(i); //undefiend
var i=1;
outPut(i); //1
}
inner();
outPut(i); //0
}
outer();
</SCRIPT>

  你可能認為輸出結果是0 0 1 0,事實上在AS中確實是這樣的,而在JS中的輸入卻是0 undefined 1 0,為何會這樣了?剛才我們說到了JS函數體中聲明的本地變數在整個函數中都有效,因此在上面代碼中var i = 1 ;在inner函數中都有效,實際上顯式聲明的變數i是在先行編譯時就已經編譯到調用對象中了,不同於隱式聲明變數在解釋時才被定義為全域變數,只是在調用outPut(i)時,還沒有將它初始設定變數,此時的本地變數i是未賦值變數,而不是未定義變數,因此輸出了undefined。上面的代碼等效於下面代碼:
複製代碼 代碼如下:
function inner(){
var i; //定義但不賦值
outPut(i); //undefiend
i=1;
outPut(i); //1
}

  為了避免上面的這類問題,因此在函數開始位置集中做函式宣告是一個極力推薦的做法。
五、基本類型和參考型別
  JS不同於JAVA、C這些語言,在變數申明時並不需要聲明變數的儲存空間。變數中所儲存的資料可以分為兩類:基本類型和參考型別。其中數值、布爾值、null和undefined屬於基本類型,對象、數組和函數屬於參考型別。
  基本類型在記憶體中具有固定的記憶體大小。例如:數值型在記憶體中佔有八個位元組,布爾值只佔有一個位元組。對於引用型資料,他們可以具有任意長度,因此他們的記憶體大小是不定的,因此變數中儲存的實際上是對此資料的引用,通常是記憶體位址或者指標,通過它們我們可以找到這個資料。
  參考型別和基本類型在使用行為上也有不同之處:
複製代碼 代碼如下:
<SCRIPT LANGUAGE="JavaScript" type="text/javascript">
//定義一個輸出函數
function outPut(s){
document.writeln(s)
}
var a = 3;
var b = a;
outPut(b);
//3
a = 4;
outPut(a);
//4
outPut(b);
//3
</SCRIPT>

  對基本類型b進行賦值時,實際上是又開闢了一塊記憶體空間,因此改變變數a的值對變數b沒有任何影響。
複製代碼 代碼如下:
<SCRIPT LANGUAGE="JavaScript" type="text/javascript">
//定義一個輸出函數
function outPut(s){
document.writeln(s)
}
var a_array = [1,2,3];
var b_array = a_array;
outPut(b_array); //1,2,3
a_array[3] = 4;
outPut(b_array);//1,2,3,4
</SCRIPT>

上面是對參考型別的變數賦值,實際上他們傳遞的是對記憶體位址的引用,因此對a_array和b_array的存取,實際上都是操作的同一塊記憶體地區。如果希望重新分配記憶體空間儲存引用型變數,那麼我就需要使用複製方法或者自訂方法來複製引用變數的資料。

JS變數範圍
複製代碼 代碼如下:
<script language ="javascript" type ="text/javascript" >
var a = "change";
function fun() {
alert(a);//輸出undefined
var a = "改變了";
alert(a);//輸出改變了
}
alert(a);//輸出change
fun();
</script>

var定義的是一個範圍上的變數,在第一次輸出a之前,JS在先行編譯分析中已經將a賦值為change,所以第一次輸出change,當調用到fun()函數的時候,JS建立一個新的範圍,在輸出a之前,初始化所有var變數的值為undefined,所以fun()中第一次輸出的是undefined,第二次輸出已經給a賦值了,所以輸出新的值;兩個a在函數裡面和外面是不同的兩個變數,如:
複製代碼 代碼如下:
<script language ="javascript" type ="text/javascript" >
var b;
function fun() {
b = "change";
}
alert(b);//輸出undefined
</script>

變數b在函數外面已經定義了,在函數中有給b賦值,但輸出的卻是undefined。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.