JS变量以及其作用域详解

转自:http://www.cnblogs.com/terryglp/articles/1776695.html

===========================================================================



一、变量的类型 


Javascript和Java、C这些语言不同,它是一种无类型弱检测的语言。

它对变量的定义并不需要声明变量类型,我们只要通过赋值的形式,可以将各种类型的数据赋值给同一个变量


i=100;//Number类型 

i="variable";//String类型 

i={x:4};//Object类型 

i=[1,2,3];//Array类型


优点编码更加灵活

弊端不利于Debug


===========================================================================



二、变量的声明 


JS中变量声明分显式申明隐式申明


var i=100; //显式声明

i=100;//隐式声明


显式声明函数中使用var关键字进行声明的变量是做为局部变量, 为显式声明。

隐式声明没有用var关键字,使用直接赋值方式声明的是全局变量,为隐式声明。


当我们使用访问一个没有声明的变量时,JS会报错

当我们给一个没有声明(注意是声明不是定义)的变量赋值时,JS不会报错,相反它会认为我们是要隐式声明一个全局变量,这一点一定要注意。


===========================================================================



三、全局变量和局部变量 


JS解析器执行时,首先就会在执行环境里构建一个全局对象我们定义的全局属性(全局变量)就是作为该对象的属性读取

在顶层代码中我们使用this关键字window对象都可以访问到它(全局变量)

函数体中局部变量在函数执行时生成的调用对象中存在,函数执行完毕时局部变量即刻销毁


===========================================================================



四、变量作用域


JS中变量的作用域相对与JAVA、C这类语言显得更自由

特征:JS变量没有块级作用域,函数中的变量在整个函数都中有效!!!

例子:

JavaScript没有块级作用域:

		function test(){
		   for(var i = 0 ; i < 3 ; i++){
		   }
		   alert(i); // i为3
		}
		test();

		相当于

		function test(){
			var i;
			for(i = 0; i < 3; i++){
			}
			alert(i); // i为3
		}
		test();

		function test() {
			var i = 1;
			if( i > 0) {
				var thisKey = 3;
			}
			else {
				var thisKey = 4;
			}
			alert(thisKey);
		}
		test();
		//虽然thisKey 是在if/else块中声明和定义的,
		//但是因为JS没有块级作用域,所以alert()可以直接访问,
		//只要他们都在同一个函数内就没有问题

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); //输出的是局部变量i   值为1 

			} 

			inner(); 

			outPut(i); //输出的是全部变量i  值为0 
		} 

		outer();
/*
输出结果为0 1 0,从上面就可以证明JS如果用var在函数体中声明变量,那么此变量在且只在该函数体内有效,函数运行结束时,本地变量即可销毁了。 
*/
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(); 
/*
你可能认为输出结果是0 0 1 0,事实上在AS中确实是这样的,
然而在JS中的输出却是0 undefined 1 0,
为何会这样了?
刚才我们说到了JS函数体中声明的本地变量在整个函数中都有效,
因此在上面代码中 var i = 1;  在inner函数中都有效,
(!!注意这句话:)实际上显式声明的变量i是在预编译时就已经编译到调用对象中了,
不同于隐式声明变量在解释时才被定义为全局变量。
所以在调用outPut(i)时,还没有*定义*i(未初始化i[没有给i赋值]),即i是undefined[未定义]的,
此时的本地变量i仅仅只是*声明*了,因此输出了undefined。
换一种理解方式:  
声明一个变量i =  告诉你存在一个变量i(不实现它),只是告诉你有这么个东西,让你开心一下
定义这个变量i =  实现这个变量i的具体情况(给i赋值->此时真正在内存[堆或栈中]给变量i分配空间)

所以上面11~15行的代码等效于下面代码:
	function inner(){ 
		var i; //定义但不赋值 
		outPut(i); //undefiend 
		i=1; 
		outPut(i); //1 
	} 

为了避免上面的这类问题,因此在函数开始位置集中做函数声明是一个极力推荐的做法。 
*/


===========================================================================



五、基本类型和引用类型 




JS不同于JAVA、C这些语言,在变量声明时并不需要声明变量的存储空间。
变量中所存储的数据可以分为两类:基本类型引用类型

数值布尔值nullundefined属于基本类型
对象数组函数属于引用类型

基本类型在内存中具有固定的内存大小:

数值型在内存中占有八个字节
布尔值只占有一个字节

引用型数据,他们可以具有任意长度,因此他们的内存大小是不定的,因此变量中存储的实际上对此数据的引用,通常是内存地址或者指针,通过它们我们可以找到这个数据。 

	function outPut(s){ //定义一个输出函数 
		document.writeln(s) 
	} 
	var a = 3; 
	var b = a; 
	outPut(b); //3 
	a = 4; 
	outPut(a); //4 
	outPut(b); //3
/*
对基本类型b进行赋值时,实际上是又开辟了一块内存空间,因此改变变量a的值对变量b没有任何影响。
*/
	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 
/*
上面是对引用类型的变量赋值,实际上他们传递的是对内存地址的引用,因此对a_array和b_array的存取,实际上都是操作的同一块内存区域。如果希望重新分配内存空间存储引用型变量,那么我就需要使用克隆方法或者自定义方法来复制引用变量的数据。
*/



展开阅读全文

没有更多推荐了,返回首页