简体   繁体   English

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

[英]JavaScript: Very strange behavior with assigning methods in a loop

Consider this code below: 请考虑以下代码:

<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>

Basically, it shows two anchors, a1 and a2, and I expect to see "1" and "2" popping up in an alert when clicking on corresponding anchor. 基本上,它显示了两个锚点a1和a2,并且我希望在单击相应的锚点时在警报中弹出“1”和“2”。 It doesn't happen, I get "2" when clicking on either. 它没有发生,点击其中任何一个时我得到“2”。 After spending an hour meditating on the code, I decided that it probably happens because dynamic onclick methods for both anchors keep the last value of "i". 在花了一个小时冥想代码之后,我决定它可能会发生,因为两个锚点的动态onclick方法保持“i”的最后一个值。 So I change that loop to 所以我将循环更改为

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

hoping that each dynamic function will get its own copy of "i" with immediate value. 希望每个动态函数都能获得具有立即值的“i”副本。 But after this change I get "1" popping up when I click on either link. 但是在这个改变之后,当我点击任一链接时,我会弹出“1”。

What am I doing wrong? 我究竟做错了什么? It's a huge show stopper for me. 这对我来说是一个巨大的表演限制。

The last value is stored, you can use closures for this: 存储最后一个值,您可以使用闭包:

<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>

This solution binds the i to the function scope, the key trick is the executing of the function inside of the loop, otherwise you are left with the end result of iterating through and alerting the last value of i . 这个解决方案将i绑定到函数作用域,关键技巧是在循环内部执行函数,否则你将留下迭代的最终结果并警告i的最后一个值。

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

This blog post explains the problem pretty well. 这篇博文很好地解释了这个问题。 The thing is that loops doesn't have their own variable scopes in JavaScript, so the inner function is using the scope of the parent function. 问题是循环在JavaScript中没有自己的变量作用域,因此内部函数使用父函数的作用域。

Don't use for (… in …) for arrays. 不要for (… in …)数组。 Use the simple for loop instead: 请改用简单的for循环:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM