JavaScript:在循环中分配方法时非常奇怪的行为

时间:2009-11-04 19:36:52

标签: javascript javascript-events

请考虑以下代码:

<a href="javascript:void(-1)" id="a1">a1</a>
<a href="javascript:void(-1)" id="a2">a2</a>

<script type="text/javascript">
    var buttons = []
    buttons.push("a1")
    buttons.push("a2")
    var actions = []
    for (var i in buttons)
    {
        actions[buttons[i]] = function() { alert(i) }
    }

    var elements = document.getElementsByTagName("a")
    for (var k = 0; k < elements.length; k++)
    {
        elements[k].onclick = actions[elements[k].id]
    }

</script>

基本上,它显示了两个锚点a1和a2,我希望在单击相应的锚点时会在警报中弹出“1”和“2”。 它没有发生,点击其中任何一个时我得到“2”。在花了一个小时冥想代码之后,我决定它可能会发生,因为两个锚点的动态onclick方法保持“i”的最后一个值。 所以我将该循环更改为

for (var i in buttons)
{
    var local_i = i.toString()
    actions[buttons[i]] = function() { alert(local_i) }
}

希望每个动态函数都能获得具有立即值的“i”副本。但是在这个改变之后,当我点击任一链接时,我会弹出“1”。

我做错了什么?这对我来说是一个巨大的阻碍。

3 个答案:

答案 0 :(得分:3)

存储最后一个值,您可以使用闭包:

<a  href="#">blah</a><br>
<a  href="#">blah</a><br>
<a  href="#">foo</a><br>

<script>
    (function() {
    var anchors = document.getElementsByTagName('a');
    for ( var i = anchors.length; i--; ) {
        var link = anchors[i];
        (function(i) {
            link.onclick = function() {
                alert(i)
            }
        })(i);
    }
    })();
</script>

此解决方案将i绑定到函数作用域,关键技巧是在循环内部执行函数,否则将留下迭代的最终结果并警告{{的最后一个值1}}。

参考:http://www.jibbering.com/faq/faq_notes/closures.html

答案 1 :(得分:2)

blog post很好地解释了这个问题。问题是循环在JavaScript中没有自己的变量作用域,因此内部函数使用父函数的作用域。

答案 2 :(得分:-1)

不要将for (… in …)用于数组。请改用简单的for循环:

for (var i=0; i<buttons.length; ++i) {
    actions[buttons[i]] = (function(i) {
        return function() {
            alert(i);
        };
    })(i);
}