在包含循环变量的循环中定义匿名函数?

时间:2011-11-30 23:51:53

标签: javascript html

我知道这段代码不起作用,我也知道原因。 但是,我不知道如何解决它:

JavaScript的:

var $ = function(id) { return document.getElementById(id); };
document.addEventListener('DOMContentLoaded', function()
{
    for(var i = 1; i <= 3; i++)
    {
        $('a' + i).addEventListener('click', function()
        {
            console.log(i);
        });
    }
});

HTML:

<a href="#" id="a1">1</a>
<a href="#" id="a2">2</a>
<a href="#" id="a3">3</a>

我希望它能够打印您点击的链接号,而不仅仅是“4”。 我宁愿避免使用节点的属性(id或content),而是修复循环。

3 个答案:

答案 0 :(得分:5)

将循环块包装在自己的匿名函数中:

document.addEventListener('DOMContentLoaded', function()
{
        for(var i = 1; i <= 3; i++)
        {
            (function(i) {
                $('a' + i).addEventListener('click', function() {
                    console.log(i);
                })
            })(i);
        }
}

这将创建一个i的新实例,它在每次调用/迭代时都是内部函数的本地实例。如果没有这个本地副本,传递给addEventListener的每个函数(在每次迭代中)都会关闭对相同变量的引用,其值等于4时的任何一个那些回调执行。

答案 1 :(得分:3)

问题是内部函数正在i创建一个闭包。从本质上讲,这意味着函数不仅仅是在设置处理程序时记住i的值,而是变量i本身;它保留了i的实时参考。

您必须通过将i传递给某个函数来打破关闭,因为这会导致i复制

执行此操作的常用方法是使用立即执行的匿名函数。

        for(var i = 1; i <= 3; i++)
        {
            $('a' + i).addEventListener('click', (function(localI)
            {
                return function() { console.log(localI); };
            })(i);
        }

由于你已经在使用jQuery,我会提到jQuery提供了一个data函数,可以用来简化这样的代码:

        for(var i = 1; i <= 3; i++)
        {
            $('a' + i).data("i", i).click(function()
            {
                console.log($(this).data("i"));
            });
        }

这里,不是通过将i传递给匿名函数来打破闭包,而是通过将i传递给jQuery的data函数来打破它。

答案 2 :(得分:0)

闭包捕获对变量的引用,而不是副本,这就是为什么它们都会导致'i'的最后一个值。

如果你想捕获一个副本,那么你需要将它包装在另一个函数中。