【问题标题】:Event handlers inside a Javascript loop - need a closure?Javascript 循环中的事件处理程序 - 需要闭包吗?
【发布时间】:2010-09-25 09:33:15
【问题描述】:

我正在处理一些我从别人那里接手的 html 和 Javascript 代码。该页面每十秒重新加载一个数据表(通过异步请求),然后使用一些 DOM 代码重新构建该表。有问题的代码如下所示:

var blah = xmlres.getElementsByTagName('blah');
for(var i = 0; i < blah.length; i++) {
    var td = document.createElement('td');
    var select = document.createElement('select');
    select.setAttribute("...", "...");
    select.onchange = function() {
        onStatusChanged(select, callid, anotherid);
    };
    td.appendChild(select);
}

但是,当为 &lt;select&gt; 元素触发 onchange 事件时,似乎对于表中的每个 &lt;select&gt; 都将相同的值传递给 onStatusChanged() 方法(我已经在每个循环的迭代,callidanotherid 被赋予新的、不同的值)。

我怀疑这是因为我使用select.onchange = function() 语法设置事件处理程序的性质。如果我理解它是如何正常工作的,那么这个语法将 onchange 事件的闭包设置为一个引用这两个引用的函数,这最终具有在循环的最后一次迭代中设置的任何值的最终值。当事件触发时,callidanotherid 引用的值是上一次迭代中设置的值,而不是单个迭代中设置的值。

有没有办法可以复制我传递给onStatusChanged()的参数值?

我已更改标题以更好地反映问题和接受的答案。

【问题讨论】:

    标签: javascript dom loops closures


    【解决方案1】:

    您确实需要在这里实现一个闭包。这应该工作(让我知道 - 我没有测试它)

    var blah = xmlres.getElementsByTagName('blah');
    for(var i = 0; i < blah.length; i++) {
        var td = document.createElement('td');
        var select = document.createElement('select');
        select.setAttribute("...", "...");
        select.onchange = function(s,c,a)
        {
            return function()
            {
                onStatusChanged(s,c,a);
            }
        }(select, callid, anotherid);
        td.appendChild(select);
    }
    

    【讨论】:

    • 另外一个我发现的解决方案 - 一个真正的解决方法 - 将 callid 和 anotherid 作为属性存储在 DOM 元素中,并在事件处理程序中通过 this.getAttribute() 引用它们
    • 我不会称其为解决方法。我期望的是让处理程序设置一次(不是每次都通过循环)并让它自己发现变量。
    • 请注意,OP 也有一个闭包。实际上,OP 具有更具代表性的形式,您的闭包与其他闭包共享其环境(每次循环运行创建一个闭包)。但这正是产生意想不到的效果的原因。
    猜你喜欢
    • 2012-01-27
    • 2015-04-05
    • 1970-01-01
    • 2011-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多