闭包的两个特点:
1、作为一个函数变量的一个引用 - 当函数返回时,其处于激活状态。
2、一个闭包就是当一个函数返回时,一个没有释放资源的栈区。
例1。
scripttype="text/javascript"
functionsayHello2(name){
vartext='Hello'+name;//localvariable
varsayAlert=function(){alert(text);}
returnsayAlert;
}
varsy=sayHello2('never-online');
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)sy();
/script
作为一个Javascript程序员,应该明白上面的代码就是一个函数的引用。如果你还不明白或者不清楚的话,请先了解一些基本的知识,我这里不再叙述。
上面的代码为什么是一个闭包?
因为sayHello2函数里有一个内嵌匿名函数
sayAlert = function(){ alert(text); }
在Javascript里。如果你创建了一个内嵌函数(如上例),也就是创建了一个闭包。
在C或者其它的主流语言中,当一个函数返回后,所有的局部变量将不可访问,因为它们所在的栈已经被消毁。但在Javascript里,如果你声明了一个内嵌函数,局部变量将在函数返回后依然可访问。比如上例中的变量sy,就是引用内嵌函数中的匿名函数function(){ alert(text); },可以把上例改成这样:
scripttype="text/javascript"
functionsayHello2(name){
vartext='Hello'+name;//localvariable
varsayAlert=function(){alert(text);}
returnsayAlert;
}
varsy=sayHello2('never-online');
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)alert(sy.toString());
/script
这里也就与闭包的第二个特点相吻合。
例2。
scripttype="text/javascript"
functionsay667(){
//Localvariablethatendsupwithinclosure
varnum=666;
varsayAlert=function(){alert(num);}
num++;
returnsayAlert;
}
varsy=say667();
sy();
alert(sy.toString());
/script
上面的代码中,匿名变量function() { alert(num); }中的num,并不是被拷贝,而是继续引用外函数定义的局部变量——num中的值,直到外函数say667()返回。
[
例3。
scripttype="text/javascript"
functionsetupSomeGlobals(){
//Localvariablethatendsupwithinclosure
varnum=666;
//Storesomereferencestofunctionsasglobalvariables
gAlertNumber=function(){alert(num);}
gIncreaseNumber=function(){num++;}
gSetNumber=function(x){num=x;}
}
/script
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)buttononclick="setupSomeGlobals()"生成-setupSomeGlobals()/button
buttononclick="gAlertNumber()"输出值-gAlertNumber()/button
buttononclick="gIncreaseNumber()"增加-gIncreaseNumber()/button
buttononclick="gSetNumber(5)"赋值5-gSetNumber(5)/button
上例中,gAlertNumber, gIncreaseNumber, gSetNumber都是同一个闭包的引用,setupSomeGlobals(),因为他们声明都是通过同一个全局调用——setupSomeGlobals()。
你可以通过“生成”,“增加”,“赋值”,“输出值”这三个按扭来查看输出结果。如果你点击“生成”按钮,将创建一个新闭包。也就会重写gAlertNumber(), gIncreaseNumber(), gSetNumber(5)这三个函数。
如果理解以上代码后,看下面的例子:
例4。
scripttype="text/javascript"
functionbuildList(list){
varresult=[];
for(vari=0;ilist.length;i++){
varitem='item'+list[i];
result.push(function(){alert(item+''+list[i])});
}
returnresult;
}
functiontestList(){
varfnlist=buildList([1,2,3]);
//usingjonlytohelppreventconfusion-couldusei
for(varj=0;jfnlist.length;j++){
fnlist[j]();
}
}
testList();
/script
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)运行结果:
item3isundefined
item3isundefined
item3isundefined
代码result.push(function(){alert(item+''+list[i])}),
使result数组添加了三个匿名函数的引用。这句代码也可以写成
varp=function(){alert(item+''+list[i])};
result.push(p);
关于为什么会输出三次都是 "item 3 is undefined"
在上面的例子say667()例子中已经解释过了。
匿名函数function() {alert(item + ' ' + list[i])}中的list[i]并不是经过拷贝,而是对参数list的一个引用。直到函数buildList()返回为止,也就是说,返回最后一个引用。即遍历完list(注:list的最大下标应该是2)后,经过i++也就变成了3,这也就是为什么是item 3,而list[3]本身是没有初始化的,自然也就是undefined了。
例5。
scripttype="text/javascript"
functionnewClosure(someNum,someRef){
//Localvariablesthatendupwithinclosure
varnum=someNum;
varanArray=[1,2,3];
varref=someRef;
returnfunction(x){
num+=x;
anArray.push(num);
alert('num:'+num+
'anArray'+anArray.toString()+
'ref.someVar'+ref.someVar);
}
}
varclosure1=newClosure(40,{someVar:'never-online'})
varclosure2=newClosure(99,{someVar:'BlueDestiny'})
closure1(4)
closure2(3)
/script
在这最后一个例子中,展示如何声明两个不同的闭包。