JavaScript学习笔记(1)变量的生命周期
变量的生命周期又称为作用域,是指某变量在程序中的有效范围。根据作用域,变量可以分为全局变量和局部变量。
1、 全局变量的作用域是全局性的,即在整个JavaScript程序中,全局变量处处都在。
2、 而在函数内部声明的变量,只在函数内部起作用。这些变量是局部变量,作用域是局部性的;函数的参数也是局部性的,只在函数内部起作用。
经常见到网上有文章说:“在JavaScript中可以有两种方式声明全局变量:1、声明变量时不使用var关键字 2、在函数外部声明变量 使用第一种方法声明变量时,就算是在函数内部,该变量仍为全局变量,使用第二种方法声明变量时,就算是用var关键字,那么声明的变量也是全局变量,” 自己亲手测试一下就知其中对错:参看如下示例:
1
<
script type
=
"
text/javascript
"
>
2 var v01 = " 我是全局变量v01 " ; // 使用var关键字声明的全局变量
3 v02 = " 我是全局变量v02 " ; // 未使用var关键字声明的全局变量
4 function fun1(){
5 alert(v01); // output "我是全局变量v01"
6 alert(v02); // output "我是全局变量v02"
7
8 v03 = " 我是全局变量v03 " ;
9 var v04 = " 我是局部变量v04 " ;
10 }
11
12 function fun2(){
13 alert(v01); // output "我是全局变量v01"
14 alert(v02); // output "我是全局变量v02"
15
16 alert(v03); // error: "v03未定义"
17 alert(v04); // error: "v04未定义"
18
19 }
20
21 fun2();
22 </ script >
2 var v01 = " 我是全局变量v01 " ; // 使用var关键字声明的全局变量
3 v02 = " 我是全局变量v02 " ; // 未使用var关键字声明的全局变量
4 function fun1(){
5 alert(v01); // output "我是全局变量v01"
6 alert(v02); // output "我是全局变量v02"
7
8 v03 = " 我是全局变量v03 " ;
9 var v04 = " 我是局部变量v04 " ;
10 }
11
12 function fun2(){
13 alert(v01); // output "我是全局变量v01"
14 alert(v02); // output "我是全局变量v02"
15
16 alert(v03); // error: "v03未定义"
17 alert(v04); // error: "v04未定义"
18
19 }
20
21 fun2();
22 </ script >
为什么结果与大家公认的不一致呢,让我们把程序做稍微的改动:
1
<
script type
=
"
text/javascript
"
>
2 var v01 = " 我是全局变量v01 " ; // 使用var关键字声明的全局变量
3 v02 = " 我是全局变量v02 " ; // 未使用var关键字声明的全局变量
4 function fun1(){
5 alert(v01); // output "我是全局变量v01"
6 alert(v02); // output "我是全局变量v02"
7
8 v03 = " 我是全局变量v03 " ;
9 var v04 = " 我是局部变量v04 " ;
10 }
11
12 function fun2(){
13 alert(v01); // output "我是全局变量v01"
14 alert(v02); // output "我是全局变量v02"
15
16 alert(v03); // output: "我是全局变量v03"
17 alert(v04); // error: "v04未定义"
18
19 }
20 //两个函数都调用
21 fun1();
22 fun2();
23 </ script >
2 var v01 = " 我是全局变量v01 " ; // 使用var关键字声明的全局变量
3 v02 = " 我是全局变量v02 " ; // 未使用var关键字声明的全局变量
4 function fun1(){
5 alert(v01); // output "我是全局变量v01"
6 alert(v02); // output "我是全局变量v02"
7
8 v03 = " 我是全局变量v03 " ;
9 var v04 = " 我是局部变量v04 " ;
10 }
11
12 function fun2(){
13 alert(v01); // output "我是全局变量v01"
14 alert(v02); // output "我是全局变量v02"
15
16 alert(v03); // output: "我是全局变量v03"
17 alert(v04); // error: "v04未定义"
18
19 }
20 //两个函数都调用
21 fun1();
22 fun2();
23 </ script >
呵呵,这个时候,程序终于按照我们原先的设想执行了,但是这个时候,我们就必须做下来好好总结一下了:
如果我们在函数内部声明了一个全局变量,也就是声明变量时未使用var关键字,当我们在其他地方使用该变量时,必须保证该函数已被调用,所以,如果真的要使用全局变量还是在函数外部声明的好
还有一个值得注意的地方就是:JavaScript变量作用范围没有语句块的概念,他并不像JAVA一样在for循环内部声明的变量,在for循环外部就不能使用,参看一下示例:
1
function
test(){
2 for ( var i = 0 ; i < 20 ; i ++ ){
3 document.write(i + " <BR> " );
4 if (i == 19 ) {
5 var j = " 我是在for语句内部声明的 " ;
6 }
7 }
8 alert(j); // output: "我是在for语句内部声明的"
9 }
10 test();
2 for ( var i = 0 ; i < 20 ; i ++ ){
3 document.write(i + " <BR> " );
4 if (i == 19 ) {
5 var j = " 我是在for语句内部声明的 " ;
6 }
7 }
8 alert(j); // output: "我是在for语句内部声明的"
9 }
10 test();
除此之外,还有一个容易引起错误的地方不能不说,参看一下程序:
1
var
strTest
=
"
全局变量
"
;
2 function test1(){
3 alert(strTest); //output: "undefined"
4 var strTest = " 看看出错没 " ;
5 }
6 test1();
先来解释一下这个小程序,我们首先在函数外部声明了一个全局性的变量,接着在函数内部把它alert出来,最后我们又声明了一个同全局变量的名字相同的一个局部变量,但是就是这个只有六行的小程序,其结果却并不像我们想象的那样输出"看看出错没",而是输出了
undefined,呵呵,看来“JavaScript真是处处是陷阱啊”!
2 function test1(){
3 alert(strTest); //output: "undefined"
4 var strTest = " 看看出错没 " ;
5 }
6 test1();
在网上GOOGLE了半天,找到了这样一种说法:
大家都知道JavaScript是一种解释型的脚本语言,当JavaScript运行时,首先查找所有的变量声明,并以未定义的初始值创建变量。如果变量被声明时有值,那么该变量仍以未定义的值初始化,并且只有在运行了声明行时才被声明值取代。
这也就解释了以上的程序,其实如果我们在程序的第一行之前加上一句:alert(strTest);输出结果依然会是
undefined,看到这我想大家应该也想到了,程序出错的原因并不是说声明了一个与全局变量名称相同的局部变量,而是只要在变量声明语句之前调用该变量,该变量的值就一定是 undefined,但是如果我们调用一个没有被声明的变量,这个时候会报“变量未定义”的错误,所以我们还必须得明白这两者之间的区别,不过不管怎么说,一种好的编码习惯还是避免把局部变量与全局变量声明称相同的名字!
在看最后一种情况:注意以下程序:
1
var
strGloblVar
=
"
我是全局变量
"
;
2 function father(){
3 strFatherGloblVar = " 在父函数中声明的全局变量 " ;
4 var strFatherVar = " 我是父函数中为局部变量,同时也是子函数中的全局变量 " ;
5 function child(){
6 strChildGloblVar = " 在子函数中声明的全局变量 " ;
7 var strChildVar = " 我是子函数中的局部变量 " ;
8 alert(strFatherVar); // output: "我是父函数中为局部变量,同时也是子函数中的全局变量"
9 alert(strChildVar); // output: "我是子函数中的局部变量"
10 alert( " 子函数中: " + strGloblVar); // output: "我是全局变量"
11 alert(strFatherGloblVar);
12 }
13 alert( " 父函数中: " + strGloblVar); // output: "我是全局变量"
14 // alert(strChildVar); //error: strChildVar 未定义
15 // alert(strChildGloblVar); //error:strChildGloblVar 未定义
16 return child();
17 }
18
19 father();
20 alert("所有函数外部:"+strFatherGloblVar); //output: "所有函数外部:在父函数中声明的全局变量"
21 alert("所有函数的外部:"+strChildGloblVar); //output:"所有函数的外部:在子函数中声明的全局变量"
用过JavaScript闭包的人会很容易的看懂以上程序,闭包不是本文要说明的重点,但是这个小例子可以帮我们证明在闭包的情况下,变量的生命周期并没有因为使用闭包而有很大的改变,可以简单的抛开闭包的概念,把father()函数内部看成一个独立的运行环境。14行报错,是因为strChildVar是child()函数中定义的局部变量,15行报错,是因为在调用strChildGloblVar之前child()函数未被执行过,这和我们之前说的都一样。但是当我们在father()函数外部打印strFatherVar的时候会出现错误,导致这种错误的原因很简单,strFatherVar虽然是child()的全局变量,但是却是father()的局部变量。
2 function father(){
3 strFatherGloblVar = " 在父函数中声明的全局变量 " ;
4 var strFatherVar = " 我是父函数中为局部变量,同时也是子函数中的全局变量 " ;
5 function child(){
6 strChildGloblVar = " 在子函数中声明的全局变量 " ;
7 var strChildVar = " 我是子函数中的局部变量 " ;
8 alert(strFatherVar); // output: "我是父函数中为局部变量,同时也是子函数中的全局变量"
9 alert(strChildVar); // output: "我是子函数中的局部变量"
10 alert( " 子函数中: " + strGloblVar); // output: "我是全局变量"
11 alert(strFatherGloblVar);
12 }
13 alert( " 父函数中: " + strGloblVar); // output: "我是全局变量"
14 // alert(strChildVar); //error: strChildVar 未定义
15 // alert(strChildGloblVar); //error:strChildGloblVar 未定义
16 return child();
17 }
18
19 father();
20 alert("所有函数外部:"+strFatherGloblVar); //output: "所有函数外部:在父函数中声明的全局变量"
21 alert("所有函数的外部:"+strChildGloblVar); //output:"所有函数的外部:在子函数中声明的全局变量"