Logo

never-online

A crisis is a terrible thing to waste.
  • Blog首页
  • 推荐日志
  • 关于我
  • 留言簿
  • 设计
  • 订阅RSS
  • 登录
« GC机制以及IE Jscrip...
neverModules - 布局... »
分类: Web Dev
推荐日志

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

[ 2006-09-18 23:38:57 | 作者: never-online ]
字体大小: 大 | 中 | 小
Close Advertisement
先把GC和Memory Leak探究暂时放下,牵涉的东西较多。需要逐一进行解释。
比如这篇文章就是其中的一个影子——闭包(closure)。
特别注明:我的翻译是很烂的...:(,而且并没有按原文那样一路译下来,我只是抽取70%左右并加了一些自己的注释。
所以建议能读懂英文的朋友,可以点击最下面的链接去读原文。

闭包的两个特点:

1。作为一个函数变量的一个引用 - 当函数返回时,其处于激活状态。
2。一个闭包就是当一个函数返回时,一个没有释放资源的栈区。

例1。
Copy Code(拷贝代码)-Run HTML(运行代码)-Save Code(另存代码)
<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>

作为一个Javascript程序员,应该明白上面的代码就是一个函数的引用。如果你还不明白或者不清楚的话,请先了解一些基本的知识,我这里不再叙述。

上面的代码为什么是一个闭包?
因为sayHello2函数里有一个内嵌匿名函数
sayAlert = function(){ alert(text); }
在Javascript里。如果你创建了一个内嵌函数(如上例),也就是创建了一个闭包。

在C或者其它的主流语言中,当一个函数返回后,所有的局部变量将不可访问,因为它们所在的栈已经被消毁。但在Javascript里,如果你声明了一个内嵌函数,局部变量将在函数返回后依然可访问。比如上例中的变量sy,就是引用内嵌函数中的匿名函数function(){ alert(text); },可以把上例改成这样:
Copy Code(拷贝代码)-Run HTML(运行代码)-Save Code(另存代码)
<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>
这里也就与闭包的第二个特点相吻合。

例2。
Copy Code(拷贝代码)-Run HTML(运行代码)-Save Code(另存代码)
<script type="text/javascript">
function say667() {
 // Local variable that ends up within closure
 var num = 666;
 var sayAlert = function() { alert(num); }
 num++;
 return sayAlert;
}

var sy = say667();
sy();
alert(sy.toString());
</script>

上面的代码中,匿名变量function() { alert(num); }中的num,并不是被拷贝,而是继续引用外函数定义的局部变量——num中的值,直到外函数say667()返回。

例3。
Copy Code(拷贝代码)-Run HTML(运行代码)-Save Code(另存代码)
<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; }
}

</script>
<button onclick="setupSomeGlobals()">生成 - setupSomeGlobals()</button>
<button onclick="gAlertNumber()">输出值 - gAlertNumber()</button>
<button onclick="gIncreaseNumber()">增加 - gIncreaseNumber()</button>
<button onclick="gSetNumber(5)">赋值5 - gSetNumber(5)</button>

上例中,gAlertNumber, gIncreaseNumber, gSetNumber都是同一个闭包的引用,setupSomeGlobals(),因为他们声明都是通过同一个全局调用——setupSomeGlobals()。
你可以通过“生成”,“增加”,“赋值”,“输出值”这三个按扭来查看输出结果。如果你点击“生成”按钮,将创建一个新闭包。也就会重写gAlertNumber(), gIncreaseNumber(), gSetNumber(5)这三个函数。

如果理解以上代码后,看下面的例子:

例4。
Copy Code(拷贝代码)-Run HTML(运行代码)-Save Code(另存代码)
<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;
}

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]();
 }
}

testList();
</script>
运行结果:
item 3 is undefined
item 3 is undefined
item 3 is undefined

代码result.push( function() {alert(item + ' ' + list[i])} ),
使result数组添加了三个匿名函数的引用。这句代码也可以写成
var p = 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。
Copy Code(拷贝代码)-Run HTML(运行代码)-Save Code(另存代码)
<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://blog.morrisjohns.com/javascript_closures_for_dummies
[最后修改由 never-online, 于 2006-09-19 02:07:24]
评论Feed 评论Feed: http://www.never-online.net/blog/feed.asp?q=comment&id=106

浏览模式: 显示全部 | 评论: 2 | 引用: 0 | 排序 | 浏览: 5035
引用 leelong*
[ 2007-05-10 11:18:20 ]
谢谢!学习到了很多东西!
引用 日尧*
[ 2008-08-27 10:41:10 ]
谢谢!学习到了很多东西!

发表
表情图标
[smile] [confused] [cool] [cry]
[eek] [angry] [wink] [sweat]
[lol] [stun] [razz] [redface]
[rolleyes] [sad] [yes] [no]
[heart] [star] [music] [idea]
UBB代码
转换链接
表情图标
悄悄话
昵        称:  3-24字符, 不可使用特殊字符 *
安全规则: 请输入规则答案: 2+5=? *
 
Language Package
  • ENGLISH
  • 简体中文
用户面板
用户名:
密码:
安全规则: 2+5=?
注册
分类
  • Blog首页
  • Android [2] Android RSS Feed
  • Diary & Misc [115] Diary & Misc RSS Feed
  • Web Dev [108] Web Dev RSS Feed
  • Never Modules(JS) [12] Never Modules(JS) RSS Feed
  • Flash & Flex & Air [4] Flash & Flex & Air RSS Feed
  • PHP & Apache [1] PHP & Apache RSS Feed
  • XML [7] XML RSS Feed
  • CSS [7] CSS RSS Feed
  • ASP & .NET [3] ASP & .NET RSS Feed
  • Literature Archives [4] Literature Archives RSS Feed
  • Design [17] Design RSS Feed
  • Visual Basic [3] Visual Basic RSS Feed
最新评论
  • @gzman 那阵子确实想蛮多...
  • 兄弟,想太多了吧
  • [smile] [wink] [sweat] ...
  • javascript:insertSmilie...
  • 我新建了两个sliderbar都...
  • 不错哦````````
  • 好文,收藏至20ju.com
  • @aflyhorse 我这里没有实...
  • 我上次找了一个识别效果...
  • 第一个实例我只看见了doe...
  • 好文啊,只是我阅读太慢...
  • 其实用<iframe src="java...
  • 还没到那个境界。
  • @tokki 要造也应该造车,...
  • 能不造轮子的程序员太少...
搜索

统计数据
日志: 283
评论: 845
引用: 0
用户: 115
到访: 4059708
在线: 1

新浪微博
Links
  • Zerray
  • realdodo
  • ps album
  • my flickr
  • XiaoFeng
  • 神~ORZ
  • Jiuan's blog
  • yanpeng's blog
  • zhoux's blog
  • winter
  • aoao
  • jerry.qu
  • JoelLeung
  • monyer
  • Miller
  • PuterJam
  • Terry
  • JK
  • akira
  • dh20156's New World!
  • muxrwc
  • Joshua
  • Estyle
  • 互联网人
  • 兔子
  • 电脑爱好者
  • 阿笨狗
Favorite
  • leica china
  • Douglas Crockford
  • dhteumeuleu
  • regexplib
  • webfx
  • ajaxian
  • John Resig
  • dean
  • Adam McCrea
  • css beauty
  • livepipe
  • smashing magazine
  • ericlippert
  • narcissus
  • PPK
widget

Powered by LBS Version 2.0.304 © 2003-2005 SiC/CYAN. - Template writen by never-online - 桂ICP备07010684号
17 DB Queries | Proccessed in 109ms