[教程]JScript中的变量引用规则
http://www.csdn.net/expert/topic/787/787738.xml
JScript中的变量引用规则。
:)
-------------------------------------
你需要的基础是,函数对象的正确认识。函数对象作为传递内容是怎样工作的。
你需要一个方便的环境,请先下载http://lostinet.d2g.com/temp/public/runscript.zip
运行 default.hta
->->->->并且学会使用这个工具。(很容易学会)
入门入门入门入门入门入门入门入门入门入门入门入门入门入门入门入门
>>>>>>>>
好了。。。
首先,运行下面这些代码:(当然是在RunScript中运行)
1。1
{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---
function GetFunc()
{
return Func;
}
function Func()
{
alert(":)");
}
var func1=GetFunc();
var func2=GetFunc();
alert(func1==func2);
---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}
很明显。显示true;
下面的代码呢?
1。2
{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---
function GetFunc()
{
return Func;
function Func()
{
alert(":)");
}
}
var func1=GetFunc();
var func2=GetFunc();
alert(func1==func2);
---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}
只有一个不同处,Func放在GetFunc中定义了。
但是令你觉得不可思议的是,alert竟然显示false
先休息5分钟,心情平服了再看下面。(不然生心脏病不要怪我哦)
请刷新一次RunScript,然后再运行下面
请刷新一次RunScript,然后再运行下面
请刷新一次RunScript,然后再运行下面
请刷新一次RunScript,然后再运行下面
请刷新一次RunScript,然后再运行下面
1。3
{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---
function GetFunc()
{
return Func;
function Func()
{
alert(":)");
}
}
alert(typeof(Func));
---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}
??? 搞不懂。。怎么alert显示"undefined" ? (你到底刷新了没有?)
Func不是已经定义了吗??
先不要学着讨论,,看更多的例子,先让自己在感觉上有个底。
1。4
{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---
var str="I love JScript";
function GetFunc()
{
var str="I am hungry now.";
return Func;
function Func()
{
return str;
}
}
alert("先不要按确定哦,看着代码,想想应该显示什么?");
alert(GetFunc()());
---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}
注:如果你觉得GetFunc()();很奇怪,那是因为你还不喜欢函数的传递。
GetFunc()返回的是一个函数。当然可以这样 (GetFunc())(); 所以这样 GetFunc()()也是正确的。
结果在这里不说了,怕被你看到。
为什么会显示这个呢?
不要想太多了。。还有很多例子要看呢。。
1。5
{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---
var str="I love JScript";
function GetFunc()
{
var str="Hungry Point:"+Math.floor(Math.random()*100+1)+"%";
return Func;
function Func()
{
return str;
}
}
var func1=GetFunc();
var func2=GetFunc();
alert(func1());
alert(func2());
alert("哦,不奇怪,str被改了一次嘛。");
alert("恩?想清楚点?是改了,然后再显示的啊");
alert("记住这个:\n"+func1()+"\n"+func2());
alert("再放一次:\n"+func1()+"\n"+func2());
---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}
你看到这里,应该发现,很有趣了。
不过你仍然觉得没有什么用。。。。5555,我白说了。
倒,,说这么多还是白说,算了,还是学别人那样,讲理论吧。。
(怎么你还没有发觉被骗了啊?)
(真不好意思,家里有同学在吵架(真的,没有骗你),大家不介意我在这里做个纪念吧。。)
(2002年6月8日,他和她又吵架了,我除了羡慕,还能怎么样呢?愿天下有情人快乐过每一天)
先说
1。1 (1。1是什么来着?观察力太低了吧?还是当我没到?)
显示true是正常的。因为GetFunc返回的都是同一个“全局”的function Func()
(当你明白了为什么我说的是““全局””时,你一定会回来和我一起看着篇文章的)
2。2 (不好意思,打错了,应该是1。2,穷啊,涂改液也买不起。)
为什么显示false?
这个问题,要涉及到function的定义问题了。
而且说明这个问题也要很长的一段文字。所以只好这样啦。。
{
function一共只有两种定义方法:
function FunctionName(/*arguments*/){/*body*/}
function (/*arguments*/){/*body*/}
很明显,一个有名字,一个没有名字。
(new Function("arguments","body")算不算?不算)
先说没有名字的那个。
没有名字的那个的一般使用方法,
一:用一个变量来引用:var func=function(){};
二:直接执行这个函数:(function(){alert("ok")})();
三:就只定义,什么都不做。function(){};(这个除了用来拖慢CPU就没有其他用途了)
还是不能理解?应该怎样理解 function(){} 呢?
我的观点是就当做 function(){} 是一个值。!!
和 var i=3;var s="ok";var b=true;一样。
为什么function就不能作为一个值来对一个变量初始化呢?
现在你不难理解
var ReportWrong=function(){alert("Wrong!!!")};
这一句了吧?它就是定义一个ReportWrong,而ReportWrong是一个函数,
它执行的是alert("Wrong!!!");
基本和
function ReportWrong(){alert("Wrong!!!")}
一样的。
但是也有不同啊,现在就说
function FunctionName(/*arguments*/){/*body*/}
这个形式。
function FunctionName(/*arguments*/){/*body*/}
是一个定义函数的形式。与其说是定义,不如说是“运行”
因为刚才提到
function FunctionName(/*arguments*/){/*body*/}
可以用:
var FunctionName=function(/*arguments*/){/*body*/}
代替的嘛。
但是又有区别哦。。
“function FunctionName(/*arguments*/){/*body*/}”
比其他语句都要优先运行。。
例如下面代码:
----------------
Alert();
function Alert()
{
alert("ok");
}
----------------
是可以的。但是其实际工作过程是:
----------------
//一:所有带名字的函数都会先运行
var Alert=function()
{
alert("ok")
};
//二:然后开始运行其他语句
Alert();
----------------
(注:还有一个不同是Alert.toString()是不同的,原因还是因为定义不同)
所以到现在,你不难理解有时见到
function window.onload()
{
}
了吧?
其实就是
window.onload=function()
{
}
}
好了,花了这么多口水,终于吧function的定义讲了。(不要意思了,吧字又写做了。口水多没有办法)
你不是忘记了该讲到哪里了吧??
现在是讲1。2的为什么alert(func1==func2)显示false的问题。
(听说用锥来刺大腿,可以提高精神的,你要不要试试?)
不记得代码了啊?帖一次:(不过建议你新开浏览器来对照。如果是书,那就买两本吧)
(不过我的笔墨那么烂,没有人请我写书啊。)
1。2
{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---
function GetFunc()
{
return Func;
function Func()
{
alert(":)");
}
}
var func1=GetFunc();
var func2=GetFunc();
alert(func1==func2);
---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}
现在就不难理解了:
1。2
{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---
function GetFunc()
{
var Func=function()
{
alert(":)");
}
return Func;
}
var func1=GetFunc();
var func2=GetFunc();
alert(func1==func2);
---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}
因为每次都是新建一个“函数对象”再返回的。
虽然func1和func2的功能相同,但是却是两个对象。
还有疑问?这个:?
function GetNumber()
{
var N=3;
return N;
}
var n1=GetNumber()
var n2=GetNumber();
alert(n1==n2)
是显示true的啊??
记住,函数是一个对象。。记住,函数是一个对象。。记住,函数是一个对象。。记住,函数是一个对象。。记住,函数是一个对象。。记住,函数是一个对象。。记住,函数是一个对象。。记住,函数是一个对象。。
类似的应该是这个:
function GetObject()
{
var O=new Object();
return O;
}
var o1=GetNumber()
var o2=GetNumber();
alert(o1==o2)
好了。1。2讲完了,下面说说1。3
{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---
function GetFunc()
{
return Func;
function Func()
{
alert(":)");
}
}
alert(typeof(Func));
---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}
为什么typeof(Func)是undefined呢?
很简单嘛,经过上面函数定义的讨论,1。3的功能和这个一样的
function GetFunc()
{
var Func=function()
{
alert(":)");
}
return Func;
}
Func是“变量空间”GetFunc的一个变量,
在全局,当然不可能直接引用Func啦。。
所以,名字是不能直接引用下一个“空间”内的变量的。
1。4在这里:
{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---
var str="I love JScript";
function GetFunc()
{
var str="I am hungry now.";
return Func;
function Func()
{
return str;
}
}
alert("先不要按确定哦,看着代码,想想应该显示什么?");
alert(GetFunc()());
---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}
现在,我们来分析两个str变量。
一个是“全局”,一个是在“GetFunc的空间”内。
先看看三个语句:
1.alert(GetFunc()());
2.return Func;
3.return str;
我们要弄清楚,这三个语句的位置。
1是在全局范围的。
2呢?是在GetFunc里面。
3就在Func里面。
当然,如果说在2.return Func前加条alert(str),学过JScript的人就知道是显示"I am hungry now."了。
而在1.alert(GetFunc()());前加alert(str),
当然alert(str)显示的是"I love JScript"了。
但是在Func下的规则呢?事实摆明一切。Func下str引用的是2.GetFunc空间里面的str;
1。4算完了。先不给讨论的机会。看完1。5再说。。
1。5
{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---
var str="I love JScript";
function GetFunc()
{
var str="Hungry Point:"+Math.floor(Math.random()*100+1)+"%";
return Func;
function Func()
{
return str;
}
}
var func1=GetFunc();
var func2=GetFunc();
alert(func1());
alert(func2());
alert("哦,不奇怪,str被改了一次嘛。");
alert("恩?想清楚点?是改了,然后再显示的啊");
alert("记住这个:\n"+func1()+"\n"+func2());
alert("再放一次:\n"+func1()+"\n"+func2());
---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}
1。5算是今天要讲的最后一个例子了。当然,你能理解这个,也只能算是入门。
而1。5的结果告诉我们。
func1和一个str关联,func2又和一个str关联。这两个str都不是全局那个。
真奇怪?不是吗?你不觉得奇怪吗?你不觉得奇怪?你真的不觉得奇怪?好了,我知道你不觉得奇怪了。你不觉得奇怪就算了嘛。干什么回答这么多次。。
我告诉觉得奇怪的人,你们觉得奇怪是因为:GetFunc只有一个,而为什么会有两个str吧???
当然,GetFunc只有一个。
不会有第二个了。但是既然Func都有两个,为什么str不能有两个呢?(觉得模糊吧?)
我来解释一下,我的观点是,(因为只是我的观点,MS,ECMA他们怎么说的我不知道)
var func1=GetFunc();时,GetFunc里面已经创建一个空间了,
就是这篇文章说的 JScript 的变量空间。(by lostinet)
暂时就叫 GetFunc_Space1 吧(注GetFunc_Space1是为了说明而写的,实际上没有这个名字)
然后 var str="Hungry Point:"+Math.floor(Math.random()*100+1)+"%";这一句,
就为 GetFunc_Space1 添加一个变量 str
而 function Func()则为 GetFunc_Space1 添加一个变量Func
在
var func2=GetFunc();时,原理和上面一样,生成的是GetFunc_Space2和这个空间的相关变量。
所以,一个GetFunc拥有两组变量的原因,就是上面说的原理了。
然后是变量引用规则:
alert(func1())的时候,到底干什么了呢???
不理alert了,直接讨论func1()干什么去了。
看看前面的代码,func1是GetFunc_Space1的Func
所以func1()
相当于运行 GetFunc_Space1::Func();
所以不难理解,为什么显示的是 GetFunc_Space1::str,而不是GetFunc_Space2::str了
因为func1,func2是直接有一个变量空间和他们联系着的。
讲到这里,也查不多了。。
现在就初步说说在Func里面,变量的搜索规则吧。。
func1 就是:
Global_Space::GetFunc_Space1::Func
那么执行func1,搜索str,是从Global_Space::GetFunc_Space1::Func_Space1开始的。
Global_Space::GetFunc_Space1::Func_Space1没有str,然后就搜索:
Global_Space::GetFunc_Space1,中就找到了Global_Space::GetFunc_Space1::str
所以
Func()里return str的str是Global_Space::GetFunc_Space1::str
可以看到,这是一个金字塔的结构。
Global_Space是顶了,然后下面开始分支。。
每个分支的函数都是先搜索自己函数的空间,(不包括下曾)
然后逐级往顶(上)层搜索,一直搜索到有名字匹配的变量为止。
如果搜不到?当然就是runtime error(xxx没有定义)了。typeof除外。
------------------------------------
入门就讲到这里啦。。我想睡了。。(倒,写了一个半小时)
以后我会继续写完这些的:(提醒自己而已)
function对象和其他的不同处,
引用关系是怎样的?
不同空间的变量的引用关系是怎样的?
变量的释放规则是怎样?
eval的工作原理。
。。。。。
思考题:
用自己的脑算算这个,然后对照结果。
{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---{---
var a=0;
function GetFunc()
{
a++;
if(a>5)
return Func;
return GetFunc(a);
function Func()
{
return a;
}
function GetFunc(b)
{
var a=b+100;
return Func;
function Func()
{
return a;
}
}
}
var arr=[];
for(var i=0;i<10;i++)arr[i]=GetFunc()();
alert(arr.join(","));
---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}---}