风舞残阳 2008-4-1 11:20
js变量作用域及可访问性的探讨
每一种语言都有变量的概念,变量是用来存储[wiki]信息[/wiki]的一个[wiki]元素[/wiki]。比如下面这个函数:
1functionStudent(name,age,from)
2{
3this.name=name;
4this.age=age;
5this.from=from;
6this.ToString=function()
7{
8return"myinformationisname:"+this.name+",age:"+this.age+",from:"+this.from;
9}
10}
Student[wiki]类[/wiki]有三个变量,分别为name(名字),age([wiki]年龄[/wiki]),from(籍贯),这三个变量构成了描述一个[wiki]对象[/wiki]的信息。当然,这里还有一个方法用来返回Student的信息。
但是,我们是不是定义了一个变量,它就能一直存在着,并且还有可能在任何地方都能被访问和使用直到其被销毁?仔细想想,上面的[wiki]需求[/wiki]是比较过分的,因为某些变量在某个功能实现后就不再利用了,但如果这个变量还存在的话,就占用了[wiki]系统[/wiki]资源了,俗语曰:“站着茅坑不拉#$%”。
于是我们对变量的及时和按需求地销毁有一个探讨的话题了。
好,切入正题吧,就本人所接触过的来讲,js中支持如下几种类型的变量,分别为:局部变量、类变量、私有变量、实例变量、静态变量和全局变量。接下来我们就一一探讨研究下。
局部变量:
局部变量一般指在{}范围内有效变量,也就是语句块内有效的变量,如:
1functionfoo(flag)
2{
3varsum=0;
4if(flag==true)
5{
6varindex;
7for(index=0;index%26lt;10;index++)
8{
9sum+=index;
10}
11}
12document.write("indexis:"+index+"%26lt;br%26gt;");
13returnsum;
14}
15//document.write("sumis:"+sum+"%26lt;br%26gt;");
16document.write("resultis:"+foo(true)+"%26lt;br%26gt;");
该代码执行后输出的结果为:“indexis:undefined”和“resultis:0”,我们可以看到希望输出的index变量的值为undefined,也就是未定义。因此我们可以发现,index变量在if语句块结束后即被销毁了。那么“sum”变量呢?这个变量在foo()函数段执行完毕后被销毁了,如果您去掉我注释的那条语句,再执行,您将会发现系统将报错。值得注意的是,如果我把上面的foo()函数改成如下:
1functionfoo(flag)
2{
3varsum=0;
4for(varindex=0;index%26lt;10;index++)
5{
6sum+=index;
7}
8document.write("indexis:"+index+"%26lt;br%26gt;");
9returnsum;
10}
您将可以看见可以输出index值("indexis:10"),这个是js和其他语言的不同地方,因为index是在for循环的{}外面定义的,因此其作用范围在foo()函数使用完毕后才销毁。
类变量:
类变量,实际上就是类的一个属性或字段或一个方法,该变量在该类的一个实例对象被销毁后自动销毁,比如我们开始时举的Student类。这个我们不多讨论,大家可以自己试一下。
私有变量:
私有变量,值得是某个类自己内部是用的一个属性,外部无法调用,其定义是用var来声明的。注意如果不用var来声明,该变量将是全局变量(我们下面将会讨论),如:
1functionStudent(name,age,from)
2{
3
4this.name=FormatIt(name);
5this.age=age;
6this.from=from;
7varorigName=name;
8varFormatIt=function(name)
9{
10returnname.substr(0,5);
11}
12this.ToString=function()
13{
14return"myinformationisname:"+origName+",age:"+this.age+",from:"+this.from;
15}
16}
17
18
这里,我们分别定义了一个origName和FormatIt()两个私有变量(按[wiki]面向对象[/wiki]的解释,应该用类的属性来称呼)。
我们把这种情况下的方法也成为变量,因为该情况下的变量是个function类型的变量,而function也属于Object类的继承类。在这种情形下,如果我们定义了varzfp=newStudent("3zfp",100,"ShenZhen")。但无法通过zfp.origName和zfp.FormatIt()方式来访问这两个变量的。
注意以下几点:
1、私有变量是不能用this来指示的。
2、私有方法类型的变量的调用必须是在该方法声明后。如我们将Student类改造如下:
1functionStudent(name,age,from)
2{
3varorigName=name;
4this.name=FormatName(name);
5this.age=age;
6this.from=from;
7varFormatName=function(name)
8{
9returnname+".china";
10}
11this.ToString=function()
12{
13return"myinformationisname:"+origName+",age:"+this.age+",from:"+this.from;
14}
15}
16varzfp=newStudent("3zfp",100,"ShenZhen");
代码执行后,将会报"找不到对象"的错误.意思是FormatName()未定义。
3、私有方法无法访问this指示的变量(公开变量),如下:
1
2functionStudent(basicinfo)
3{
4this.basicInfo=basicinfo;
5
6varFormatInfo=function()
7{
8this.basicInfo.name=this.basicInfo.name+".china";
9}
10FormatInfo();
11
12}
13functionBasicInfo(name,age,from)
14{
15this.name=name;
16this.age=age;
17this.from=from;
18}
19varzfp=newStudent(newBasicInfo("3zfp",100,"ShenZhen"));
20
21
执行代码后,系统将会提示“this.basicInfo为空或不是对象”的错误。
基本结论是,私有方法只能访问私有属性,私有属性在声明并赋值后可以在类的任何地方访问,
实例变量:
实例变量即某个实例对象所拥有的变量。如:
1
2functionBasicInfo(name,age,from)
3{
4this.name=name;
5this.age=age;
6this.from=from;
7}
8varbasicA=newBasicInfo("3zfp",100,"ShenZhen");
9basicA.generalInfo="is3zfpowned[wiki]object[/wiki]";
10document.write("basicA'sgeneralInfois:"+basicA.generalInfo+"%26lt;br%26gt;");
11varbasicB=newBasicInfo("zfp",100,"ShenZhen");
12document.write("basicB'sgeneralInfois:"+basicB.generalInfo+"%26lt;br%26gt;");
13执行该代码后,我们将可以看到如下结果:
14basicA'sgeneralInfois:is3zfpownedobject
15basicB'sgeneralInfois:undefined
16
静态变量:
静态变量即为某个类所拥有的属性,通过类名+"."+静态变量名的方式访问该属性。如下可以做清晰的解释:
1functionBasicInfo(name,age,from)
2{
3this.name=name;
4this.age=age;
5this.from=from;
6}
7BasicInfo.generalInfo="is3zfpownedobject";
8varbasic=newBasicInfo("zfp",100,"ShenZhen");
9document.write(basic.generalInfo+"%26lt;br%26gt;");
10document.write(BasicInfo.generalInfo+"%26lt;br%26gt;");
11BasicInfo.generalInfo="infoischanged";
12document.write(BasicInfo.generalInfo+"%26lt;br%26gt;");
执行以上代码,将会得到如下结果:
undefined
is3zfpownedobject
infoischanged
注意以下几点:
1、以类名+"."+静态变量名的方式来声明一个静态变量
2、静态变量并不属于类的某个实例对象所独有的属性,为对象的[wiki]共享[/wiki].
3、能以实例对象名+"."+静态变量名来访问。
全局变量:
全局变量即整个系统运行期间有效访问控制的变量,通常是在一个js代码开头定义,如:
1
2varcopyright="3zfpowned";
3varfoo=function()
4{
5window.alert(copyright);
6}
注意以下几点:
1、如果一个变量不用var来声明,则其被视为全局变量。如:
1varcopyright="3zfpowned";
2varfoo=function(fooInfo)
3{
4_foo=fooInfo;
5document.write(copyright+"%26lt;br%26gt;");
6}
7newfoo("footest");
8document.write(_foo+"%26lt;br%26gt;");
执行代码,将得到如下结果:
3zfpowned
footest
但是,这个又有一个注意的地方,function是编译期对象,也就是说_foo这个全局变量要在foo对象被实例化后才能被初始化,也就是说如果将
newfoo();
document.write(_foo+"%26lt;br%26gt;");
对调成
document.write(_foo+"%26lt;br%26gt;");
newfoo();
系统将提示"_foo未定义"。
2、如果定义了一个和全局变量同名的局部变量属性,如下:
1
2
3varcopyright="3zfpowned";
4varfoo=function(fooInfo)
5{
6varcopyright=fooInfo;//同名变量
7this.showInfo=function()
8{
9document.write(copyright+"%26lt;br%26gt;");
10}
11}
12newfoo("footest").showInfo();
13document.write(copyright+"%26lt;br%26gt;");
执行代码,将得到如下结果:
3zfpowned
footest
原因是由于function是在编译期间完成变量的定义,也就是foo内部的copyright的定义是在编译期间完成的,其作用域只在foo对象内有效,而与外部定义的全局变量copyright无关。