介绍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) - 上

    相关文章