【问题标题】:Adding events to elements inside loop - JScript/Closures向循环内的元素添加事件 - JAVAScript/Closures
【发布时间】:2011-07-18 01:04:15
【问题描述】:

我正在构建一个按钮列表,我希望每个按钮都使用当前 members[member].id 触发 addForm() 函数。

但碰巧只有最后一个按钮会触发该事件。

我知道它与闭包有关,如您所见,我已经调整了函数以使用这种模式。

我做错了什么?

function displayConnections(connections) {
    /*(...)*/

    for (var member in members) {

        connectionsDiv.innerHTML += "<p>" + members[member].firstName + " " + members[member].lastName
        + " ID: " + members[member].id;

        btn = document.createElement("input");
        btn.setAttribute("type","button");
        btn.setAttribute("value","Send Message");
        btn.setAttribute("id",members[member].id);

        btn.onclick = function (id) {
            return function () {
                addForm(id);
            };
        }(members[member].id);

        connectionsDiv.appendChild(btn);

    }     
}

谢谢。

【问题讨论】:

    标签: javascript scope closures


    【解决方案1】:

    首先,请记住您不是在编写 C# 或 Java。 for (var ... in ...) 结构不会迭代集合。您应该始终检查hasOwnProperty 以查看属性名称是否属于对象本身:

    if (!members.hasOwnProperty(member)) continue;
    

    然后检查以确保属性值是对象而不是函数等。

    其次,您的变量 btn 缺少 var 声明。您正在创建一个名为btn全局 变量,而不是您的函数的本地变量。

    接下来,您的原始代码中有拼写错误。您的原始代码实际上是这样解释的(感谢 JavaScript 的自动分号插入功能!):

    btn.onclick = function (id) {
        return function () {
            addForm(id);     <-- this id is now the click event's event object, not what you want
        };
    };
    (members[member].id);   <-- this line will have no side effect
    

    为了以你原来的风格运行你的程序,你需要把函数定义括起来:

    btn.onclick = (function (id) {
        return function () {
            addForm(id);
        };
    })(members[member].id);
    

    【讨论】:

    • 我认为你在简化闭包方面是错误的 - members[member].id 将在每次通过循环时继续更改。
    • 这个更正仍然给了我最后一个按钮来触发事件。
    【解决方案2】:

    好吧,您也可以使用以下解决方法:

    element.setAtrribute('onClick', 'javascript:functionName(' + parameter + ');');
    

    这对我有用,也应该对你有用。

    【讨论】:

      【解决方案3】:

      在这段代码中:

      btn.onclick = function (id) {
          return function () {
              addForm(id);
          };
      }(members[member].id);
      

      您的语法错误 - 应该是:

      btn.onclick = (function(id) {
          return function () {
              addForm(id);
          }
      })(members[member].id);
      

      这样做是自动调用一个新的匿名闭包,它在其id 参数中具有members[member].id 的本地绑定副本,然后它本身返回一个闭包实际上是绑定到btn.onclick

      只有在闭包声明周围加上外括号时才会发生自动调用。

      【讨论】:

      • 通过您的更正,只有最后一个按钮会触发该事件。
      【解决方案4】:
      for (var i = 0; i < 10; i++) {
      
          // Won't work
          //$('div').eq(i)[0].onclick = function() { alert(i) }; // 10
      
      
          $('div').eq(i)[0].onclick = (function(id) {
              return function() {
                  alert(id)
              };
          })(i);
      }
      

      jsFiddle.

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-31
        • 1970-01-01
        • 2015-12-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多