开发者

JavaScript: Very strange behavior with assigning methods in a loop

开发者 https://www.devze.com 2022-12-10 01:51 出处:网络
Consider this code below: <a href=\"javascript:void(-1)\" id=\"a1\">a1</a> <a href=\"javascript:void(-1)\" id=\"a2\">a2</a>

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. It doesn't happen, I get "2" when clicking on either. After spending an hour meditating on the code, I decided that it probably happens because dynamic onclick methods for both anchors开发者_如何学Go keep the last value of "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. But after this change I get "1" popping up when I click on either link.

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.

Reference: 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.


Don’t use for (… in …) for arrays. Use the simple for loop instead:

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

精彩评论

暂无评论...
验证码 换一张
取 消