介紹JavaScript中的變數(Variables)的用法,包含宣告(Declare)、指派(Assign)與變數範圍(Scope),以及識別子(Identifier)的格式。

 

1. 簡介

變數是用來儲存資料和進行運算的基本程式功能,我們必須為變數指定一個合適的名稱,才能進一步操作,例如:

var data = 2012;
var data2 = data + 1;	// 2013

2. 宣告(Declare)

JavaScript中使用var的關鍵字進行變數宣告,而未給定初始值的變數值為undefined:

var n;
var m = 1;
console.log(n);	// undefined

也可以使用逗點(,)隔開連續宣告:

var x, y;
var flag = true, num = 0;
var n, m = 1;

2.1 省略var

JavaScript中允許省略var關鍵字來給定變數初始值,所有省略var關鍵字建立的變數皆為全域變數:

function func() {
	var L = 'local';
	G = 'global';
}
func();
console.log(G);	// global
// error
//console.log(L);

應該避免省略var變數,以免所有資料都存放在全域變數,造成資源的消耗,甚至是程式出錯。

2.2 未宣告

雖然JavaScript允許省略var關鍵字來給未曾出現過的變數指派值,但是他卻不允許其他情況使用未曾出現過的變數,如上面的例子,對於func之外的地方,L變數未曾宣告過,故會發生錯誤。

JavaScript中會先解析var關鍵字,所以即使程式後面才出現宣告,前面就先使用了也不算是未宣告,算是宣告而未給初始值:

console.log(m);	// undefined
var m = 1;

2.3 重複宣告

JavaScript允許程式重覆宣告變數,不過實際上他不會進行重覆宣告,最多只會將其視為指派資料值:

var i = 1;
var i;
console.log(i);	// 1, 不是undefined
var i = 2;
console.log(i);	// 2

3. 識別字(Identifier)

程式中使用到的變數或函式名稱都必須符合識別字的格式,格式基本上和大多數程式語言的命名規則一樣,可使用英文字母、數字、底線(_)或錢號($)組合,但開頭不能是數字,正規表示法如下

[a-zA-Z_$][a-zA-Z0-9_$]*

以上是我們通常使用的規則,除此之外,JavaScript也支援Unicode的字元,所以實際上合法的開頭字元完整如下:

  1. 底線(_)
  2. 錢號($)
  3. 合法的開頭Unicode字元

合法的開頭Unicode字元如下:

  1. Uppercase letter(大寫字母)
  2. Lowercase letter(小寫字母)
  3. Titlecase letter
  4. Modifier letter
  5. Other letter
  6. Letter number

識別字第二個字母開始可用字元完整如下:

  1. 合法的開頭字元
  2. Decimal number(數字)
  3. Non-spacing mark
  4. Combining spacing mark
  5. Connector punctuation

另外也可以使用\uxxxx跳脫字元的格式來表示,使用跳脫字元的格式表示時,可以使用原本不能使用的關鍵字作為變數,一些範例如下:

var user = 'dindin';
var User = 'lala';
console.log(user, User);	// dindin lala, 大小寫有差別

// 以下皆為合法的變數名稱
var no456;
var _55 = 66;
var $5 = 'NT150';
var lälä = '偽物';
var 中文 = '也行';
var \u0069\u0066 = 'if';

// 以下為SyntaxError
//var 3m = '300cm';
//var \u0030 = 0;
//var if = '\u0069\u0066';

4. 指派(Assign)

JavaScript的資料型態依據其特性可分成兩類:

  1. 基本型態(Primitive type)
  • 布林
  • 數值
  • 空值(null)
  • 未定義(undefined)
  • 參考型態(Reference type)
    • 陣列
    • 物件
    • 函式

    基本型態的資料型態所佔用的記憶體大小是固定的,而在指派或傳遞則是使用傳值(pass by value)的方式傳遞複本;參考型態則正好相反,資料所佔用大小是不固定的,使用傳址(pass by reference)的方式:

    var year = 2012;
    var year2 = year;
    ++year2;
    console.log(year);		// 2012
    
    var obj = {year: 2012};
    var obj2 = obj;
    ++obj2.year;
    console.log(obj.year);	// 2013
    
    var str = 'y';
    var str2 = str;
    str2 += 'if';
    console.log(str);		// y
    

    字串沒有被寫出來,因為他比較特殊,字串是屬於大小不固定的資料型態,然而實際上我們在使用的時候,他的表現行為卻是基本型態。在較底層的實作上,字串使用傳址的方式效能才會比較好,不過實務上的需求是要像基本型態一樣操作,所以可以想成底層幫你處理掉這複雜的機制,簡單的當作基本型態使用即可。

    5. 變數範圍(Scope)

    程式中我們可能會在不同的位置,用到相同的變數名稱,表示不同的東西,如果變數沒有範圍就可能會互相干擾。所以在程式中,會有不同的變數範圍,當程式離開這個範圍之後,其他地方就不能使用此範圍的變數。JavaScript中的變數範圍有全域變數(global)和區域變數(local),每個函式都會建立一個區域變數的範圍,而最外層的部分則是全域變數的範圍。

    函式可以是巢狀的結構,所以區域變數也可以是巢狀的,內部的範圍可以使用外部範圍的變數,而當變數名稱相同的時候則以內部的優先:

    var str = 'global';
    function local() {
    	var str = 'local';
    	function nest()  {
    		var str = 'nest';
    		console.log(str);	// nest
    	}
    	nest();
    	console.log(str);		// local
    }
    local();
    console.log(str);			// global
    

    JavaScript中沒有區塊描述(block statement)的區域變數範圍,他的區域變數範圍只出現在函式:

    if(true) {
    	var str = 'not local';
    }
    console.log(str);	// not local
    

    如2.1節所說,由於var關鍵字會先被解析,所以在一旦在區域變數範圍內出現和全域變數相同名稱的變數,就會先被宣告而隱藏全域變數,即使程式尚未執行到,如下範例所示:

    var str = 'global';
    function local() {
    	console.log(str);	// undefined, 不是global
    	var str = 'local';
    	console.log(str);	// local
    }
    local();
    

    5.1 window

    程式開始執行時,JavaScript會建立一個全域物件,所有的全域變數都會存放在這個物件中,物件中包含一個window屬性指向自己,所以在使用上我們可以使用window這個變數來取得最上層的全域物件,進一步取得全域變數:

    var str = 'global';
    console.log(window.str);		// global
    
    function local() {
    	var str = 'local';
    	console.log(window.str);	// global
    	console.log(str);			// local
    }
    local();
    

    5.2 移除全域變數

    在之前的文章有提到delete運算子可以用來移除變數,同時也提到了只能用來移除物件屬性建立的變數,所以不同的寫法有些全域變數可以移除有些不行:

    var a = 1;
    console.log(window.a);			// 1
    console.log(delete window.a);	// false
    window.b = 2;
    console.log(window.b);			// 2
    console.log(delete window.b);	// true
    // also work
    // console.log(delete b);
    c = 3;
    console.log(window.c);			// 3
    console.log(delete window.c);	// true
    
    function f1() {
    }
    console.log(typeof(f1));		// function 
    console.log(delete window.f1);	// false
    window.f2 = function () {
    };
    console.log(typeof(f2));		// function 
    console.log(delete window.f2);	// true
    

    延伸閱讀

    上一篇 JavaScript教學 - 資料型態(Data Type) - 下

    下一篇 JavaScript教學 - 運算子(Operators) - 上

    相关文章