js 中的作用域

你是否被js 中的作用域搞的头晕脑胀,今天我们系统的梳理一下,首先看两个例子

function show(){
		var arr = new Array();
		for(var i=0;i<5;i++){
			arr[i] = function(){
				return i;
			}
		}
		return arr;
	}
	var a = show();
	var num = a[2]();
	document.write(num);

 输出num 的值是几 ,你的答案是 2?

 恭喜你答错了!答案应该是5。

 我又修改了一下,看下面这段程序,输出num的值是几?

function show1(){
		var arr = new Array();
		for(var i=0;i<5;i++){
			arr[i] = (function(num){
				
				return function(){
					return num;
				}
			})(i);
		}
		return arr;
	}
	var a1 = show1();
	document.write(a1[2]());

    你的答案是几,是2?恭喜你猜对了,如果这两段程序,你都说出了正确答案,剩下的内容就不用看了!

   首先我们看第一个问题,JS 中的块级作用域,函数级作用域,全局作用域

   

function show(){
		for(var i=0;i<5;i++){
		}
		document.write(i);
	}
show();

          输出i的值是几,熟悉java 的童鞋可能会说,这个会报错。但是这里会输出5

 为什么呢?

      在js 中没有块级作用的概念,只有函数级作用域和全局作用域的概念。在这里定义的i 在整个show 函数内都有效。for 循环执行完 i 的值就变成了5.

      在看另一个例子

       

var color = "red";
	function show(){
		document.write(color);
		var color = "blue";
	}
show();

 输出color 是 red,blue ,还是别的什么?red,恭喜你又猜错了!

这个地方是undefined!

为什么?在这个地方涉及到两个作用域,一个是全局作用域,一个是函数(show)作用域。在js 中定义的每个方法,js 引擎都会帮我们封装一个叫变量对象的东西,这个对象默认包含argumengs 这样的一个对象,在一个就是包含你在函数里定义的变量。在这里也就是你在show 方法里定义的 var color = 'blue' 。所以我们show 方法的这个变量对象包括两个变量,一个是arguments ,一个是color ,它的值是blue。

在show 方法里document.write(color);访问color 时有两个变量可以选择,一个是全局作用的color 它的值是red ,另外一个就是show 方法里的color 它的值是blue。根据js 作用域链访问就近原则,这里访问的是show 方法作用域的color ,那应该输出blue 才对啊,可是代码从上往下执行,当你document.write(color)时,color还没赋值呢,因为赋值语句在下面,所以这个地方输出的是undifined !如果你把函数里的var color = "blue"; 给注释掉,document.write(color);输出的就是red了。当访问color 时,先看一下函数作用域内有没有定义的color ,如果有就访问函数作用域的,如果没有就访问全局作用域的。

        有了上面的准备,我们在回过头来说一下开头的两个例子,第一个例子中的show 方法定义了 两个变量arr 和 i ,加上arguments  ,也就是说show 方法里的这个变量对象有3个变量。

       

       先看 arr 这个数组,数组中存放了5个函数对象,这5个函数对象访问的是show 方法的变量对象的 i 的值。

       一般情况下,当函数调用完,函数的变量对象自动销毁,但是对于当前的例子,show方法的变量对象不能释放,因为在调用完函数后,var a = show(); a这个变量持有arr 这个数组。而arr 里面的函数持有show 方法的变量对象。而show 方法只有一个变量对象,也只有一个i变量,所以a 这个数组里面的函数访问的都是该变量i。等到循环结束后,i 的值为5,所以数组里的函数的返回值都是5。

       而在开头的第二个例子中,

arr[i] = (function(num){
				
				return function(){
					return num;
				}
			})(i);

     我们通过函数的调用,进行值传递,将i 的值传给了变量 num ,等到show1 方法调用完,我们不在持有show1 方法变量对象的i 这个变量。所以得出答案是2。

     你是否对js 中的作用域有了更深的了解。

       

猜你喜欢

转载自pb-water.iteye.com/blog/2388008