深入理解JavaScript的变量作用域[转]
- 十二月 8th, 2009
晚上没事看了看《ActionScript3.0基础教程》。以前一直认为ActionScript和Javascript师出同门,应该是极为相似的,不过看了一下还是有些区别的。比如ActionScript是可以严格控制数据类型的,并且函数作用域相比Javascript来说更为明晰。限于本人是这两种语言的超级菜鸟,顺便goole了一篇很不错的关于JavaScript变量作用域的文章,备忘。
原文地址:http://www.cnblogs.com/rainman/archive/2009/04/28/1445687.html
在学习JavaScript的变量作用域之前,我们应当明确几点:
a、JavaScript的变量作用域是基于其特有的作用域链的。
b、JavaScript没有块级作用域。
c、函数中声明的变量在整个函数中都有定义。
1、JavaScript的作用域链
首先看下下面这段代码:
<script type="text/javascript" language="javascript">
var rain = 1;
function rainman(){
var man = 2;
function inner(){
var innerVar = 4;
alert(rain);
}
inner(); //调用inner函数
}
rainman(); //调用rainman函数
</script>
观察alert(rain);这句代码。JavaScript首先在inner函数中查找是否定义了变量rain,如果定义了则使用inner函数中的rain变量;如果inner函数中没有定义rain变量,JavaScript则会继续在rainman函数中查找是否定义了rain变量,在这段代码中rainman函数体内没有定义rain变量,则JavaScript引擎会继续向上(全局对象)查找是否定义了rain;在全局对象中我们定义了rain = 1,因此最终结果会弹出’1′。
作用域链:JavaScript需要查询一个变量x时,首先会查找作用域链的第一个对象,如果以第一个对象没有定义x变量,JavaScript会继续查找有没有定义x变量,如果第二个对象没有定义则会继续查找,以此类推。
上面的代码涉及到了三个作用域链对象,依次是:inner、rainman、window。
2、函数体内部,局部变量的优先级比同名的全局变量高。
<script type="text/javascript" language="javascript">
var rain = 1; //定义全局变量 rain
function check(){
var rain = 100; //定义局部变量rain
alert( rain ); //这里会弹出 100
}
check();
alert( rain ); //这里会弹出1
</script>
3、JavaScript没有块级作用域。
这一点也是JavaScript相比其它语言较灵活的部分。
仔细观察下面的代码,你会发现变量i、j、k作用域是相同的,他们在整个rain函数体内都是全局的。
<script type="text/javascript" language="javascript">
function rainman(){
/**
* rainman函数体内存在三个局部变量 i j k
*/
var i = 0;
if( 1 ){
var j = 0;
for( var k = 0 ; k < 3 ; k++ ){
alert( k ); //分别弹出 0 1 2
}
alert( k ); //弹出3
}
alert( j ); //弹出0
}
</script>
4、函数中声明的变量在整个函数中都有定义。
首先观察这段代码。
<script type="text/javascript" language="javascript">
function rain(){
var x = 1;
function man(){
x = 100;
}
man(); //调用man
alert( x ); //这里会弹出 100
}
rain(); //调用rain
</script>
上面得代码说明了,变量x在整个rain函数体内都可以使用,并可以重新赋值。由于这条规则,会产生“匪夷所思”的结果,观察下面的代码。
<script type="text/javascript" language="javascript">
var x = 1;
function rain(){
alert( x ); //弹出 'undefined',而不是1
var x = 'rain-man';
alert( x ); //弹出 'rain-man'
}
rain()
</script>
这是由于在函数rain内局部变量x在整个函数体内都有定义( var x= ‘rain-man’,进行了声明),所以在整个rain函数体内隐藏了同名的全局变量x。这里之所以会弹出’undefined’是因为,第一个执行alert(x)时,局部变量x仍未被初始化。
所以上面的rain函数等同于下面的函数。
function rain(){
var x;
alert( x );
x = 'rain-man';
alert( x );
}
5、未使用var关键字定义的变量都是全局变量。
<script type="text/javascript" language="javascript">
function rain(){
x = 100; //声明了全局变量x并进行赋值
}
rain();
alert( x ); //会弹出100
</script>
这也是JavaScript新手常见的错误,无意之中留下的许多全局变量。
6、全局变量都是window对象的属性
<script type="text/javascript" language="javascript"> var x = 100 ; alert( window.x );//弹出100 alert(x); </script>
等同于下面的代码:
<script type="text/javascript" language="javascript"> window.x = 100; alert( window.x ); alert(x); </script>
附录:一些比较BT的有关全局变量和局部变量的测试
<script>
/*
* javascript 的全局变量与局部变量一直都是一个头疼的问题,今天在写程序的时候有出现了个问题。在ie7下,在函数里就可以访问全局变量,而在ie6
* 下面居然变量的值变成了undefined。
* 以前网上查到的资料都是在定义变量的时候不使用var就定义的是全局变量,但为什么就不行了呢?
* 我就写了下面的测试程序:
*/
/*----------------------------------------*/
/*
a = 1; //A 此处为全局变量
var b = 2; //B 此处为全局变量
function params(){
alert(a); //程序输出为1
alert(b); //程序输出为2
}
params();
*/
/*----------------------------------------*/
/*
a = 1; //A 此处为全局变量
var b = 2; //B 此处为全局变量
function params(){
var a = 11; //C 此处为局部变量
var b = 22; //D 此处为局部变量
alert(a); //程序输出为11
alert(b); //程序输出为22
}
params();
alert(a); //程序输出为1
alert(b); //程序输出为2
*/
/*----------------------------------------*/
/*
a = 1; //A 此处为全局变量
var b = 2; //B 此处为全局变量
function params(){
a = 11; //C 修改全局变量a的值
b = 22; //D 修改全局变量b的值
alert(a); //程序输出为11
alert(b); //程序输出为22
}
params();
alert(a); //程序输出为11
alert(b); //程序输出为22
*/
/*----------------------------------------*/
/*
a = 1; //A 此处为全局变量
var b = 2; //B 此处为全局变量
function params(){
var a = 11; //C 此处为局部变量
var b = 22; //D 此处为局部变量
alert(a); //程序输出为11
alert(b); //程序输出为22
alert(window.a);//程序输出为1
alert(window.b);//程序输出为2
}
params();
alert(a); //程序输出为1
alert(b); //程序输出为2
*/
/*----------------------------------------*/
/*
a = 1; //A 此处为全局变量
var b = 2; //B 此处为全局变量
function params(){
a = 11; //C 修改全局变量a的值
b = 22; //D 修改全局变量b的值
alert(a); //程序输出为11
alert(b); //程序输出为22
alert(window.a);//程序输出为11
alert(window.b);//程序输出为22
}
params();
alert(a); //程序输出为11
alert(b); //程序输出为22
*/
/*----------------------------------------*/
/**
* 从以上的测试程序,应该明白全局变量和局部变量.
* 个人觉得访问全局变量,如果只需兼容ie,最好使用 window.a 这种方式来访问.
*/
</script>
猜猜以下代码输出什么:
<SCRIPT LANGUAGE="JavaScript">
var x='000';
document.writeln(x);
a();
function a(){
var x='aaa';
function b(){
document.writeln(x);
var x='bbb';
document.writeln(x);
}
b();
document.writeln(x);
}
</SCRIPT>
答案:000 undefined bbb aaa
改一下代码,得到 000 undefined 111 111:
<SCRIPT LANGUAGE="JavaScript">
var x='000';
document.writeln(x);
a();
function a(){
function b(){
document.writeln(x);
document.writeln(x);
}
document.writeln(x);
var x='111';
b();
}
</SCRIPT>
猜猜以下代码会输出什么:
<SCRIPT LANGUAGE="JavaScript">
var x=100;
document.writeln(x);
add(x);
document.writeln('</br>------------------------</br>');
var x=200;
document.writeln(x);
add(x);
function add(x){
document.writeln(x);
var x=300;
document.writeln(x);
var x=400;
document.writeln(x);
}
</SCRIPT>
估计很多人能得出正确答案:
100 100 300 400
————————
200 200 300 400
