闭包,小考题

来源:互联网 发布:windows vim 全屏 编辑:程序博客网 时间:2024/05/16 19:03

三个按钮,希望点击第一个按钮显示 0,第二个按钮显示 1,第三个按钮显示 2。怎么做呢?

<input type="button" id="b0" value="0" />
<input type="button" id="b1" value="1" />
<input type="button" id="b2" value="2" />

<script type="text/javascript" src="http://www.cftea.com/js/ezj_v2.9/ezj.js"></script>
<script type="text/javascript">
<!--
for (var i = 0; i < 3; i++)
{
    $("b" + i).click(function(){
        alert(i);
    });
}
//-->
</script>

以上代码是错误的,因为不论点哪个按钮,都是显示 3。

这是由于 i 经过 for 循环后,变成了 3,再点击按钮,始终用的是 i 的最终值,那如下代码是不是正确了呢?

for (var i = 0; i < 3; i++)
{
    var m = i;
    $("b" + i).click(function(){
        alert(m);
    });
}

也不对,这个闭包的 m 在 alert 所处的 function 之外,也就是说不受 function 保护,仍会受到 for 循环的改变,function() 中的 m 值永远是外层 m 的最后值,点任何一个按钮都会显示 2(i 在循环内的最后值)。

正确的做法

for (var i = 0; i < 3; i++)
{
    (function(i){
        $("b" + i).click(function(){
            alert(i);
        })
    })(i);
}

// 等效于下面的:

for (var i = 0; i < 3; i++) 

    function f(i)
    { 
        $("b" + i).click(function(){ 
            alert(i); 
        }) 
    }
    f(i);
}

注意 function(i) 中的 i 不能省略,否则 alert(i) 仍然是 for 循环的 i。

另外还有一种方法,和上面的代码是一个道理,不过是借助了 ezj 中,click 可以向事件处理程序传送 DOM 对象的原理,我们可以发现 click 中的 function() 变成了 function(e)

for (var i = 0; i < 3; i++)
{
    var b = $("b" + i);
    b.alertText = i;
    b.click(function(e){
        alert(e.alertText);
    });
}

备注:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
简言之,闭包是产生一个没有被释放资源的栈区。换言之,就是一个不可控的内存空间占用,如果与事件相关联,JS的垃圾回收机制也不会去触碰该区域。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------