深入了解JavaScript之作用域

1.没有块级作用域

Javascript没有块级作用域这个特点被《JavaScript语言精粹》列为js几大毒瘤之一。

正是因为没有块级作用域,所以在代码块(括在一对花括号中的一组语句)中声明的变量在包含此代码块的函数的任何位置都是可见的。

function fn(o){
	if(o){
		var j=10;
	}
	console.log(j);
}
fn(1);     //可以打印出10
在if语句里定义了变量j。如果在C、C++、Java中,j会在执行完if语句完毕后就被销毁,但是在js里,if语句的变量声明会将变量添加到当前的执行环境。

尤其是使用for语句时候要更加牢记这一点,

for(var i=0;i<10;i++){
	//dosomething(i);
}
console.log(i);  //10

对于for语句里面的i值是很容易犯错的。

举个在Js作用域与作用域链详解--Skycrab的专栏的小例子,

<html>
<head>
<script type="text/javascript">
function buttonInit(){
	for(var i=1;i<4;i++){
		var b=document.getElementById("button"+i);
		b.addEventListener("click",function(){ alert("Button"+i);},false);
	}
}
window.οnlοad=buttonInit;
</script>
</head>
<body>
<button id="button1">Button1</button>
<button id="button2">Button2</button>
<button id="button3">Button3</button>
</body>
</html>

但是作者在文章里并没有给出解决方案,其实,对于这样的问题,

等到click各个button时,就是i在循环结束之后,i就等于4了,所以弹出的都是Button4,解决这样的问题就可以用this,用this.index绑定各个button的i值。

<html>
<head>
<script type="text/javascript">
function buttonInit(){
	var b=document.getElementsByTagName("button");
	for(var i=0;i<3;i++){
		b[i].index=i;
		b[i].addEventListener("click",function(){
			alert("Button"+(this.index+1));
		},false);
	}
}
window.οnlοad=buttonInit;
</script>
</head>
<body>
<button id="button1">Button1</button>
<button id="button2">Button2</button>
<button id="button3">Button3</button>
</body>
</html>

这样就可以实现点击按钮弹出第几个按钮的效果了。偶然间看到了高程设计书上的例子,感觉用IIFEimmediately-invoked function expression,立即执行函数)会更好一点。

把buttonInit函数改成这样就好了。

function buttonInit(){
	var b=document.getElementsByTagName("button");
	for(var i=0;i<3;i++){
		(function(i){
			b[i].οnclick=function(){
				alert("Button"+(i+1));	
	    	}
	    })(i);
	}
}

这样看起来代码更加清爽,而且也不用再引入新的参数了。


2.作用域链

每一个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都得保存在这个对象里,只有在解析器处理数据的时候才会在后台使用它,

在web浏览器里,全局执行环境就是window对象,每个函数都有自己的执行环境。

当代码在一个环境中执行的时候会创建变量对象的一个作用域链。以便可以保证对执行环境有权访问的所有变量和函数的有序访问。

全局执行环境的变量对象始终都是作用域链中的最后一个对象。

var color="blue";
function changeColor(){
	if(color==="blue"){
		color="red";
	}else{
		color="blue";
	}
}
changeColor();
console.log("Color is now "+color);    //red

函数changeColor()的作用域链包含两个对象,它自己的变量对象(arguments对象)和全局的变量对象。

这个例子说明了函数内部可以访问到全局变量。


var color="blue";
function changeColor(){
	var anothercolor="red";
	function swapColors(){
		var tempColor=anothercolor;
		anothercolor=color;
		color=tempColor;
        //这里可以访问color和anothercolor和tempcolor
	}
    //这里可以访问color和anothercolor,但不能访问tempcolor
}
//这里只能访问color
changeColor();

上面的例子一共有3个执行环境:全局环境、changeColor()的局部环境和swapColors()的局部环境。

全局环境中有一个变量color和一个函数changeColor()。

changeColor()的局部环境中一个名为anotherColor的变量和一个swapColors()的函数,但它可以访问全局环境中的变量color。

swapColors()的局部环境中有一个变量tempColor,该变量只能在这个环境中访问到,无论全局环境还是changeColor()环境中都无权访问tempColor。

在外部环境访问访问不到的局部变量的话,不会Undefined,而是会Uncaught ReferenceError: *** is not defined.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值