鸟食轩

 Microsoft .NET[C#] MVP 2003
随笔 - 424, 文章 - 233, 评论 - 5417, 引用 - 344
数据加载中……

原来JScript中的关键字'var'还是有文章的

    都不记得是什么时候看的JScript的语法教程了,里面说在声明变量时忽略var关键字是完全合法的。当时也因为觉得JavaScript是loosely-typed的语言,所以var可能真的就是个摆设。但是事实常常又证明想当然的结果是不可靠的

    看看下面这几个例子的结果就知道问题了:

    No.1

<script language="javascript">
var var00 = 0;
document.write(var00 
+ '<br>');

var var01 = 1;
function foo()
{
    document.write(var01); 
    
var var01 = 1;
}

foo();
</script>


    No.2

<script language="javascript">
var00 
= 0;
document.write(var00 
+ '<br>');

var01 
= 1;
function foo()
{
    document.write(var01); 
    var01 
= 1;
}

foo();
</script>


    No.3

<script language="javascript">
var00 
= 0;
document.write(var00 
+ '<br>');

var01 
= 1;
function foo()
{
    document.write(var01); 
    
var var01 = 1;
}

foo();
</script>


    这三个例子的执行结果分别是:

Results

     原来JavaScript的变量也是有作用域的,只是它非常的笼统,就分为全局变量和函数变量。在第二个例子中得到0和1,是因为所有的变量都是全局变量,而且那个语句块一共就定义了两个变量。而第一个第三的函数外全局变量,确实说明var关键字有没有都没有关系。而函数内的var关键字就很关键了,它说明第二个var01是函数内的变量,所以在初始化var01前输出自然就是'undefined'了。

     那么函数里面是不是就屏蔽掉了全局的var01了呢?我们知道在C/C++可以使用::去访问全局变量,那么JavaScript可不可以呢?这里其实我们只要明白了全局变量到底是什么东西,就好弄了。原来全局变量都是动态添加到Window对象的实例window上的属性而以,所以我们只要在函数内用:document.write(window.var01);就可以取到其值1了。同时在这个上下文中,function内的this也是指向的window实例,我们也可以把引用写成:this.var01。

    By the way, 重看JScript教程时,它说变量只能是[a-zA-Z_]+[a-zA-Z0-9_]*格式,可是'$'却也可以作为变量名字符,而且还可以用在开头,比如:$1234,更甚至于:$$$ 也是合法的变量名,faint。

posted on 2005-01-26 23:32 birdshome 阅读(5924) 评论(34)  编辑 收藏 所属分类: Jscript&Dhtml开发

评论

#1楼    回复  引用    

<script type="text/javascript">
<!--
//这样写js的语句块更好一些:)
-->
</script>
2005-01-27 02:49 | lulu [未注册用户]

#2楼    回复  引用    

哦,还有这样的说法阿
2005-01-27 03:15 | robaggio [未注册用户]

#3楼    回复  引用  查看    

兄台,如果Js没有运行于IE宿主上的时候全局变量如何处理的呢?

我先试试啊。
2005-01-27 09:05 |       

#4楼    回复  引用  查看    

如下,怎样在foo中取得foo外面的tmp?

var tmp = 1;

function foo()
{
    
var tmp = 2;
    
return tmp;
}

WScript.Echo(
"foo:" + foo());
WScript.Echo(
"global:" + tmp);
2005-01-27 09:15 |       

#5楼    回复  引用  查看    

我想知道是不是.在调用一个函数时,程序执行顺序会先检查函数内部变量中,有没有关键字var. 然后中再根据检查结果给不同的变量付予不同的作用域和变量值.因为我看到在这三个函数中,var01变量都是在输出语句之后.

#6楼    回复  引用    



function get_global_var(___name)
{
return eval(___name);
}
function set_global_var(___name,___value)
{
eval(___name+"=___value");
}


var aa=11;
Test();
WScript.Echo(aa);//22

function Test()
{
var aa=33;

WScript.Echo(get_global_var("aa"));//11
set_global_var("aa",22);
WScript.Echo(get_global_var("aa"));//22

WScript.Echo(aa);//33
}


更多的可以参考我的一篇老文章:
http://www.csdn.com.cn/web/2088.htm
2005-01-27 09:47 | Lostinet [未注册用户]

#7楼    回复  引用  查看    

......看来除了这种方法没啥其他的了,不知楼主有啥想法。
2005-01-27 11:25 |       

#8楼 [楼主]   回复  引用  查看    

var aa=11;
Test();
WScript.Echo(aa);//22

function Test()
{
  var aa=33;
  WScript.Echo(this.aa);//11
  this.aa = 22;
  WScript.Echo(this.aa);//22
  WScript.Echo(aa);//33
}
2005-01-27 11:48 | birdshome      

#9楼    回复  引用  查看    

var aa=11;
Test();
WScript.Echo(aa);//22

function Test()
{
  var aa=33;
  WScript.Echo(this.aa);//11
  this.aa = 22;
  WScript.Echo(this.aa);//22
  WScript.Echo(aa);//33
}

WScript.Echo(new Test().aa);


这是何解呢?真被Script搞糊涂了。这样一说那个this又指Test,又指global了?
2005-01-28 09:52 |       

#10楼 [楼主]   回复  引用  查看    

  在上面的例子中this从来就没有指过Test,而一直都是WScript的实例。
  如果我们写一个语句:var test = new Test(); 这时Test里的this就是指的Test的一个实例了,这个实例中如果要使用Global的变量,Lostinet给出的是一个方法。
  不过最简单还是把global传入对象,这样定义Test:
  function Test(global)
  {
    // ...
  }
  然后这样创建实例:var test = new Test(this); 就可以在Test实例中使用global的对象和属性了。
2005-01-28 10:53 | birdshome      

#11楼    回复  引用  查看    

是不是这样,在new的实例中,this就指实例,否则都指WScript?
 
如果这样的话,换了脚本引擎,是不是情况又会不同?这个是标准吗?
2005-01-31 12:04 |       

#12楼 [楼主]   回复  引用  查看    

new constructor[(arguments)];
new 运算符执行下面的任务:
·创建一个没有成员的对象。
·为那个对象调用构造函数,传递一个指针给新创建的对象作为 this 指针。
·然后构造函数根据传递给它的参数初始化该对象。

要注意的是即使当前作用域内没有调用new,但可能在其父作用域里是调用了new的,所以“在new的实例中,this就指实例,否则都指WScript?”,前半句对,而后半句不一定。
2005-01-31 12:16 | birdshome      

#13楼 [楼主]   回复  引用  查看    

btw: Lostinet 推荐的他写的那篇文章很有看头,强烈推荐
2005-01-31 12:17 | birdshome      

#14楼    回复  引用    

如下,怎样在foo中取得foo外面的tmp?


获取全局的 tmp

window.tmp
2005-02-16 18:27 | boynannan [未注册用户]

#15楼    回复  引用    

它有局部和整体之分
个人认为还是不忽视为佳
2005-06-06 18:14 | 鬼吧 [未注册用户]

#16楼    回复  引用    

<script language="javascript">
var00 = 0;
document.write(var00 + '<br>');

var01 = 1;
function foo()
{
document.write(var01);

}
foo();
</script>
这就就显示
0
1
<script language="javascript">
var00 = 0;
document.write(var00 + '<br>');

var01 = 1;
function foo()
{
document.write(var01);

}
foo();
</script>
这就显示
0
undefined
2005-07-06 16:39 | 孙玉婷 [未注册用户]

#17楼    回复  引用    

就如楼主的列子,比如第一个和第三个,我想是不是因为在function中,是不允许定义函数的,比如在第一个列子中,
function foo()
{document.write(var01);
var var01;
}
我觉得,只所以他输出是显示undefined,是因为那个function把输出语句后面的那个
---var ar01 当成了一个变量,而这个变量很明显在前面是没有定义的,所以,他会显示undefined,而第二个之所以会显示正确的数据,就是因为在他的function内,所有的变量都是前面定义过的,他只是拿过来用,当然是没有错的。由此,我估计是不是在function内是不能再定义新的变量的,只能使用原来的???
2005-08-14 00:38 | phornic [未注册用户]

#18楼    回复  引用    

To phornic:
其实函数内的变量都是先定义,后赋值的,不管定义变量的语句写在何处。比如,
function foo()
{
document.write(var01);
var var01=1;
document.write(var02);
var var02=2;
}
该函数等价于:
function foo()
{
var var01;
var var02;
document.write(var01);
var01 = 1;
document.write(var02);
var02 =2;
}

所以在执行document.write(var01)时,变量只是定义了,而没有被赋值,所以输出undefined.
照着这个思路就不难理解前面的三个函数了。
2006-10-18 13:46 | zengdj [未注册用户]

#19楼    回复  引用    

楼住的文章有残缺
function Foo(name, color){
/*
构造函数: 对象创建时最先执行
*/
Foo.foos++;
/*
私有变量- 只可以供私有或专有函数访问!!!
注: 'name' 和 'color', 传递进Foo类时已成为私有变量.
*/
var age = 0;
var legs = 2;
function growOlder(){
age++;
}
/*
共有变量- 可供共有或私有成员访问
*/
this.weight = 1;
this.heigth = 5;
/*
专有函数 - 可供共有或私有成员访问
可访问私有变量.
Foo类外部不能更改, 只可以覆盖
*/
this.age = function(){
if(age==0) this.heigth+=20;
growOlder();
this.weight++;
}
}

/*
原型函数- 可公共访问
*/
Foo.prototype = {
hello: function(){ alert('Doutu!');
}

/*
原型变量- 可公共访问.
不可以重写, only replaced with a public version
*/
Foo.prototype.type = 'man';

/*
静态变量或函数- 可公共访问
*/
Foo.foos = 0;
2006-11-13 00:07 | Doutu [未注册用户]

#20楼    回复  引用    

其实在函数内部外部定义变量,只要注意一下,尽量不重名就可以了,是容易避免也容易发现的。可有一个地方是很容易忽视的,大家也都是习惯这么写的。
在C’s之类的语言中都可以在循环体内部声明循环变量,比如
for(int i=0; i<nLength; i++)
{
.............
.............
}
我想大多数的人会用个i来做循环变量的。
但Javascript却没有这样的语法,不允许在循环的声明中声明循环变量,因此多数人基本就省了,也就是都会这样写:
for(i=0; i<nLength; i++)
{
.............
.............
}
,这样写没有任何问题,不过,如果我们在这个循环体内部又定义了一个函数,而且这个函数又定义了一个同样的循环时,就会出现问题了。因为两个函数中的i都没有在函数内部定义,因此全都被定义成了全局变量,所以在子函数中更改了i,同样会影响到父函数中的i,这样是不会得到我们想要的结果的。
以后大家在嵌套函数的过程中都使用循环体时,尽量使用不同的循环变量,或者在各自的函数中使用var 显式声明一下循环变量就不会有这样的问题了
2007-04-27 14:17 | 寒虫露草 [未注册用户]

#21楼 [楼主]   回复  引用  查看    

@寒虫露草
你在哪里看到有规定了不建议写: for ( var i=0 ; i < n ; ++i ) 这样的申明?
2007-04-27 20:19 | birdshome      

#22楼    回复  引用  查看    

汗。。。还有后文所。。。
2007-06-08 21:03 | 尝试       

#23楼 [楼主]   回复  引用  查看    

@尝试
谢谢你的讨论,这里还有一篇和var也有点关系的文章:
http://www.cnblogs.com/birdshome/archive/2006/10/14/undefined.html
2007-06-08 21:04 | birdshome      

#24楼    回复  引用  查看    

我最近也写了一些javascript文章,请多指教。
2007-07-28 14:49 | Truly      

#25楼    回复  引用    

@birdshome

写了也没有用啊

var i = 1;
function Test()
{
var aa = 33;
i = i + 1;
// 22
for(var i = 0 ; i < 3; i ++ )
{
aa = aa + i;
for(var i = 0 ; i < 3; i ++ )
{
aa = aa + i;
}
}

alert(aa);
// 33
alert(i);
}
Test();

alert(i);
2007-09-25 14:39 | fhvsbgmy [未注册用户]

#26楼    回复  引用    

留痕。。原来这里面还有这些文章。。受教。
2008-07-22 18:18 | 张雅锋 [未注册用户]

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2005-01-27 01:37 编辑过


相关链接: