| 在javascript中,什么是闭包(Closure) |
|
| 在javascript中,什么是闭包(Closure) |
|
| |
|
闭包的两个特点:
1、作为一个函数变量的一个引用 - 当函数返回时,其处于激活状态。 2、一个闭包就是当一个函数返回时,一个没有释放资源的栈区。
例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> 作为一个Javascript程序员,应该明白上面的代码就是一个函数的引用。如果你还不明白或者不清楚的话,请先了解一些基本的知识,我这里不再叙述。
上面的代码为什么是一个闭包? 因为sayHello2函数里有一个内嵌匿名函数 sayAlert = function(){ alert(text); } 在Javascript里。如果你创建了一个内嵌函数(如上例),也就是创建了一个闭包。
在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>这里也就与闭包的第二个特点相吻合。
例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; }
var sy = say667(); sy(); alert(sy.toString()); </script> 上面的代码中,匿名变量function() { alert(num); }中的num,并不是被拷贝,而是继续引用外函数定义的局部变量——num中的值,直到外函数say667()返回。
例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; } }
</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。
<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。
<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>
在这最后一个例子中,展示如何声明两个不同的闭包。
 |
频道声明:本频道的文章除部分特别声明禁止转载的专稿外,可以自由转载.但请务必注明出出处和原始作者 文章版权归本频道与文章作者所有.对于被频道转载文章的个人和网站,我们表示深深的谢意。
| 原始作者:佚名 |
录入时间:2006-12-5 3:08:03 |
| 信息来源:不详 |
投稿信箱:itqoo@126.com |
|
|
 |
|
|
|
| 教程录入:itqoo 责任编辑:itqoo |
|
上一个教程: JS的IE和Firefox兼容性汇编
下一个教程: 没有了 |
| 【字体:小 大】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口】 |