在Javascript中,什么是闭包(Closure)

『本文地址:http://v3.djasp.net/Static/lt/2012.stm

闭包的两个特点:
此内容来源于 ★点击设计★ http://www.djasp.Net 网页编程资讯官方网站!
1、作为一个函数变量的一个引用 - 当函数返回时,其处于激活状态。
2、一个闭包就是当一个函数返回时,一个没有释放资源的栈区。
请勿盗版 ★点击设计★ http://www.djasp.Net 网站上的内容,谢谢合作!
例1。 
以下是引用片段:
<script type="text/javascript"> 
function sayHello2(name) { 
 var text = ’Hello ’ + name; // local variable 
 var sayAlert = function() { alert(text); } 
 return sayAlert; 

var sy = sayHello2(’never-online’); 
sy(); 
</script> 
此内容来源于 ★点击设计★ http://www.djasp.Net 网页编程资讯官方网站!

作为一个Javascript程序员,应该明白上面的代码就是一个函数的引用。如果你还不明白或者不清楚的话,请先了解一些基本的知识,我这里不再叙述。
★点击设计★ http://www.djasp.Net 专业的WEB编程资讯技术站点,欢迎访问!
上面的代码为什么是一个闭包?
因为sayHello2函数里有一个内嵌匿名函数
sayAlert = function(){ alert(text); }
在Javascript里。如果你创建了一个内嵌函数(如上例),也就是创建了一个闭包。
本文由 点击设计 http://www.djasp.Net 收集整理。谢绝无聊之人转载!
在C或者其它的主流语言中,当一个函数返回后,所有的局部变量将不可访问,因为它们所在的栈已经被消毁。但在Javascript里,如果你声明了一个内嵌函数,局部变量将在函数返回后依然可访问。比如上例中的变量sy,就是引用内嵌函数中的匿名函数function(){ alert(text); },可以把上例改成这样: 
以下是引用片段:
<script type="text/javascript"> 
function sayHello2(name) { 
 var text = ’Hello ’ + name; // local variable 
 var sayAlert = function() { alert(text); } 
 return sayAlert; 

var sy = sayHello2(’never-online’); 
alert(sy.toString()); 
</script> 
★点击设计★ http://www.djasp.Net 专业的WEB编程资讯技术站点,欢迎访问!
这里也就与闭包的第二个特点相吻合。
★点击设计★ http://www.djasp.Net 专业的WEB编程资讯技术站点,欢迎访问!
例2。 
以下是引用片段:
<script type="text/javascript"> 
function say667() { 
 // Local variable that ends up within closure 
 var num = 666; 
 var sayAlert = function() { alert(num); } 
 num++; 
 return sayAlert; 

本文由 ★点击设计★ http://www.djasp.Net 收集整理。谢绝无聊之人转载!
var sy = say667(); 
sy(); 
alert(sy.toString()); 
</script> 
本文由 ★点击设计★ http://www.djasp.Net 收集整理。谢绝无聊之人转载!

上面的代码中,匿名变量function() { alert(num); }中的num,并不是被拷贝,而是继续引用外函数定义的局部变量——num中的值,直到外函数say667()返回。
盗版它人网站的内容可耻,您查看的内容来源于★点击设计★www.djasp.Net
例3。 
以下是引用片段:
<script type="text/javascript"> 
function setupSomeGlobals() { 
 // Local variable that ends up within closure 
 var num = 666; 
 // Store some references to functions as global variables 
 gAlertNumber = function() { alert(num); } 
 gIncreaseNumber = function() { num++; } 
 gSetNumber = function(x) { num = x; } 

本文由 点击设计 http://www.djasp.Net 收集整理。谢绝无聊之人转载!
</script> 
<button onclick="setupSomeGlobals()">生成 - setupSomeGlobals()</button> 
<button onclick="gAlertNumber()">输出值 - gAlertNumber()</button> 
<button onclick="gIncreaseNumber()">增加 - gIncreaseNumber()</button> 
<button onclick="gSetNumber(5)">赋值5 - gSetNumber(5)</button> 
请勿盗版 ★点击设计★ http://www.djasp.Net 网站上的内容,谢谢合作!

上例中,gAlertNumber, gIncreaseNumber, gSetNumber都是同一个闭包的引用,setupSomeGlobals(),因为他们声明都是通过同一个全局调用——setupSomeGlobals()。
你可以通过“生成”,“增加”,“赋值”,“输出值”这三个按扭来查看输出结果。如果你点击“生成”按钮,将创建一个新闭包。也就会重写gAlertNumber(), gIncreaseNumber(), gSetNumber(5)这三个函数。
本文由 点击设计 http://www.djasp.Net 收集整理。谢绝无聊之人转载!
如果理解以上代码后,看下面的例子:
请勿盗版 ★点击设计★ http://www.djasp.Net 网站上的内容,谢谢合作!
例4。 以下是引用片段:
<script type="text/javascript"> 
function buildList(list) { 
 var result = []; 
 for (var i = 0; i < list.length; i++) { 
 var item = ’item’ + list[i]; 
 result.push( function() {alert(item + ’ ’ + list[i])} ); 
 } 
 return result; 

请勿盗版 ★点击设计★ http://www.djasp.Net 网站上的内容,谢谢合作!
function testList() { 
 var fnlist = buildList([1,2,3]); 
 // using j only to help prevent confusion - could use i 
 for (var j = 0; j < fnlist.length; j++) { 
 fnlist[j](); 
 } 

★点击设计★ http://www.djasp.Net 全力打造WEB技术站点,欢迎大家访问!
testList(); 
</script> 
运行结果: 
item 3 is undefined 
item 3 is undefined 
item 3 is undefined 
本文由 ★点击设计★ http://www.djasp.Net 收集整理。谢绝无聊之人转载!
代码result.push( function() {alert(item + ’ ’ + list[i])} ), 
使result数组添加了三个匿名函数的引用。这句代码也可以写成 
var p = function() {alert(item + ’ ’ + list[i])}; 
result.push(p); 
请勿盗版 ★点击设计★ http://www.djasp.Net 网站上的内容,谢谢合作!

关于为什么会输出三次都是 "item 3 is undefined"
本文由 点击设计 http://www.djasp.Net 收集整理。谢绝无聊之人转载!
在上面的例子say667()例子中已经解释过了。
匿名函数function() {alert(item + ’ ’ + list[i])}中的list[i]并不是经过拷贝,而是对参数list的一个引用。直到函数buildList()返回为止,也就是说,返回最后一个引用。即遍历完list(注:list的最大下标应该是2)后,经过i++也就变成了3,这也就是为什么是item 3,而list[3]本身是没有初始化的,自然也就是undefined了。
此内容来源于 ★点击设计★ http://www.djasp.Net 网页编程资讯官方网站!
例5。 
以下是引用片段:
<script type="text/javascript"> 
function newClosure(someNum, someRef) { 
 // Local variables that end up within closure 
 var num = someNum; 
 var anArray = [1,2,3]; 
 var ref = someRef; 
 return function(x) { 
 num += x; 
 anArray.push(num); 
 alert(’num: ’ + num +  
 ’\nanArray ’ + anArray.toString() +  
 ’\nref.someVar ’ + ref.someVar); 
 } 

var closure1 = newClosure(40, {someVar:’ never-online’}) 
var closure2 = newClosure(99, {someVar:’ BlueDestiny’}) 
closure1(4) 
closure2(3) 
</script> 
★点击设计★ http://www.djasp.Net 专业的WEB编程资讯技术站点,欢迎访问!

在这最后一个例子中,展示如何声明两个不同的闭包。
★点击设计★ http://www.djasp.Net 专业的WEB编程资讯技术站点,欢迎访问!
文章来源:http://blog.morrisjohns.com/javascript_closures_for_dummies

本文统计
上一篇: Javascript数组sort方法的分析
下一篇: 用户体验:JS实现仿新浪信息提示效…
文章类别:Javascript
最后更新:2006-10-14 9:29:55
浏览次数:
本栏最新文章
本栏推荐文章
随机酷站设计秀
网站导航 |走进点击 |点击作品 |服务项目 |联系我们 |设为首页 |加入收藏 |在线留言
点击设计
点击设计© Version: 2.3 WEB执行标准:W3C XHTML 1.1 / CSS 2.0 / Ajax
本站全面兼容 IE、FireFox、Netscape、Opera 等内核的浏览器
版权所有:点击设计 www.djasp.Net E-mail:djasp@qq.com
全程开发:秋水天子(Folier) QQ:39886616
版权所有:点击设计 www.djasp.net
浙ICP备05074939号