在一个函数中(或类定义中),有用var定义的变量为局部变量,没有定义就赋值的是全局变量。没有定义就使用的,IE提示错误“'x'未定义”。
好象很简单,但自己实际去试一下才发现问题多多。
我写一个函数,然后在VS2005中调试,我就想看一看在开发环境如何看出是局部变量与全局变量。
function abc()
{
var i=0;
a=1;
i=a;
}
abc();
var o1=abc;
alert(o1.i); //提示undefined
alert(a); //提示1
debugger; //快速监视this,但找不到a,只有监视this.a才出现
结果,虽然a是正确地提示出来,但我无法在快速监视this中看到a,只有快速监视this.a才能看到。这里的this为window。VS2008会如何?(后面,在调试中的局部窗口中可以看到this的东西)
如果用类的方式来写:
var abc=function()
{
var i;
a=1; //相当于构造函数
i=a;
}
var o1=new abc();
alert(o1.i);
alert(a);
debugger;
得到的结果是一样的,我都监视不到明显的类的属性。
对比我的函数写法,以及别人的类写法,发现一个学习点:
var o1=abc; //让o1等于abc,因此其它地方可以执行o1();也就是执行abc();,
typeof(o1)="function"
var o1=abc(); //执行abc,并把返回值给o1,typeof(o1)="undefined"
var o1=new abc(); //o1为类abc的实例,该代码也会执行函数abc,不过这美其名曰“构造函数”,typeof(o1)="object"
对比一下,发现还是“外国的月亮圆”,别人的代码强!
再对比一下,还有function的写法不一样,下面的写法被称为匿名函数,上面的写法则是普通写法,但据说上面写的同时,javaScript也生成了一个同名对象。
我再找,总算在VS2005中找到了它,以及前面提到的私有变量与全局变量。在“调试”菜单的“窗口”子菜单的“局部变量”中可以看到对应的局部变量。
有了这个窗口,我现在应该敢怀疑这句话“上面写的同时,javaScript也生成了一个同名对象”,或者我理解错了作者原意。反正,系统里面只有一个该名字的对象,其typeof的值为function,而不是该名字的对象有两个,一个object,一个function。
function比string这些简单类型更牛的是:function可以这样
abc.i=2;
而string这些简单类型就不能这样了:
var s="OK";
s.i=9; //这样也不行:s.prototype.i=9;
存取全局变量速度比局部变量要慢得多
用以下网页来验证
<html>
<head>
<script>
var a = new Date();
a1();
document.write((new Date() - a) + ":");
a = new Date();
a2();
document.write((new Date() - a) + " ");
a = new Date();
a3();
document.write((new Date() - a) + ":");
a = new Date();
a4();
document.write((new Date() - a) + " ");
//设置全局变量
function a1()
{
var i;
for (i=0; i<100000; i++)
{
b=1;
}
}
//设置局部变量
function a2()
{
var i;
var b;
for (i=0; i<100000; i++)
{
b=1;
}
}
//读取全局变量
function a3()
{
var i;
c=2;
var b;
for (i=0; i<100000; i++)
{
b=c;
}
}
//读取局部变量
function a4()
{
var i;
var c=2;
var b;
for (i=0; i<100000; i++)
{
b=c;
}
}
</script>
</head>
<body>
</body>
</html>
执行结果为:109:78 94:62 不是固定这个值,但能说明全局变量比局部变量慢30-40%。看来“存取全局变量速度比局部变量要慢得多”这句话没错!
如果要频繁使用全局变量,可以设定一个局部变量,先把全局变量拷贝过来再使用。
这句会不会又有什么问题?
如果是向上面的测试代码,拷贝过来应该是没有问题的。但如果全局变量是在变化之中的话,拷贝过来会跟着变化吗?
以下代码做这个测试:
<html>
<head>
<script>
function a1()
{
var i;
a=2;
var b;
b=a;
a=3;
alert(b); //显示2
b=4;
alert(a); //显示3
}
function a2()
{
var i;
a=new Object();
var b;
b=a;
a.i=5;
alert(b.i); //显示5
b.i=6;
alert(a.i); //显示6
}
function a3()
{
var i;
a=new Object();
var b;
b=a;
a.i=5;
alert(b.i); //显示5
a=new Object();
a.i=6;
alert(b.i); //显示5
}
a1();
a2();
</script>
</head>
<body>
</body>
</html>
测试时发现,如果a是简单类型,b=a也只是值的拷贝,因此如果全局变量变化了,不会反映到局部变量。如果a是对象类型,b=a就是地址的拷贝,因此如果全局变量下面的属性变化了,可以反映到局部变量中。但如果是a变成新的对象时,b的引用又不对了。
因此可以说,要想用拷贝全局变量来加快速度,程序员要考虑在使用过程中是否值有没有被更改,或对象有没有新建过。
VS进入到with时,会有什么反应
<html>
<body>
<script>
var i=12;
var a=new Object();
a.i=5;
a.j=6;
with (a)
{
temp=i;
i=j;
j=temp;
}
alert(i);
</script>
</body>
</html>
从代码中要记住with的格式,后面带一个圆括号,中间为想节省的对象,后面再带一个代码块。中间如果有使用对象的属性,就自动引用,而使用非对象的属性,则当做外面的普通变量处理。
进入with后,VS好象没有什么变化,至少“局部变量”窗口没有什么变化。但提示功能中对i的提示,就自动使用a.i的值了。出来后,又继续提示全局变量i的值了。
这里看,用于with确实可能造成一定的混乱,难怪JsLint不建议使用。
我现在编写javascript还没到会用try...catch的地步,先小试一个:
<html>
<body>
<script>
{
var a=b;
}
catch(e)
{
alert(" e.name:" + e.name + "\n" +
" e.message:" + e.message + "\n" +
" e.number:" + e.number.toString(16) + "\n" +
"e.description:" + e.description);
a=1;
}
finally
{
alert(a);
}
</script>
</body>
</html>
有点像VB中的on error goto xxx。如果按照我的编程原则,对已知的错误,要想办法避免,对未知的错误,应该要提示出来,并且程序停止(就是使用系统自带的功能),这样用户才会有向你报怨。对无法避免的已知错误,才需要使用on error goto xxx。我在JavaScript中太多未知的错误,因此至今还没有哪个需要用到try来防止错误重复发生。
这里会提到try...catch是因为变量e只是在catch作用区内才有效,但我测试时,却发现事实却非如此。e好象是全程有效。因此取名不要乱取,不要与其它全局变量重名了。