【问题标题】:JavaScript closures. Access in loop to current i, j variables [duplicate]JavaScript 闭包。循环访问当前 i,j 变量[重复]
【发布时间】:2013-09-04 19:46:59
【问题描述】:

我尝试使用 jQuery 动态生成<table>,并且我想为每个单元格设置单击处理程序,因此当单击单元格时,弹出窗口将显示当前单元格的索引。如何在循环中访问 CURRENT ij 变量?

  for(var i = 0; i < 5; i++) {
      var tr = $('<tr></tr>');
      for (var j = 0; j < 5; j++) {
          var td = $('<td></td>');
          td.click(function() {
            alert(i + ' ' + j);  // here I want to access to CURRENT i, j variables
          })
          td.appendTo(tr);
      }
  }    

【问题讨论】:

  • 我会将事件委托给表
  • 仅供参考,您始终可以直接从元素中获取表格行和单元格的索引。因此,在您的处理程序中,您可以执行this.cellIndex 来获取&lt;td&gt; 的索引。对于行,只要循环索引与行索引对齐,您就可以执行 this.parentNode.rowIndex
  • @user2736012 啊,谢谢你提醒我.cellIndex.rowIndex - 我忘记了表格有这些,而其他元素需要你倒数兄弟姐妹。

标签: javascript jquery


【解决方案1】:

其他答案主要解释了如何解决闭包问题,尽管这些方法的内存效率不是特别高,因为它们最终会为 ij 的每个可能组合创建一个新的闭包。

但是,由于您使用的是 jQuery,因此您可以使用许多其他选项:

data 参数传递给.on 调用

td.on('click', { i: i, j: j }, function(event) {
    var i = event.data.i;
    var j = event.data.j;
    alert(i + ' ' + j);
});

您在上面看到的ij 值将在event.data 中可用

使用$.each 代替for 进行迭代

$.each(Array(5), function(i) {
    // i is already bound here because it's a function parameter
    $.each(Array(5), function(j) {
        // and j available here
        td.on('click', ...);
    });
});

使用事件委托而不是每个元素的处理程序

$('#myTable').on('click', 'td', function() {
    // use jQuery methods to determine the index, e.g.
    var j = this.cellIndex
    var i = this.parentNode.rowIndex
    ...
});

这比将单独的处理程序单独绑定到每个&lt;td&gt; 更有效。

更一般地说,使用.data() 来存储每个单元格的信息

您可以将数据值直接存储在元素上,如果您想检索除单元格和行索引之外的值,这将非常有效:

td = $('<td>').data({i: i, j: j});

然后直接从被点击元素的.data中提取这些行列值:

for (var i = 0; i < 5; i++) {
    var tr = $('<tr></tr>');
    for (var j = 0; j < 5; j++) {
        $('<td></td>').data({i: i, j: j}).appendTo(tr);
        td.appendTo(tr);
    }
}

$('#myTable').on('click', 'td', function() {
    var data = $(this).data();
    var i = data.i;
    var j = data.j;
    alert(i + ' ' + j);
});

【讨论】:

  • +1 用于提供出色的替代方案、良好的建议和精心编写的解释。
【解决方案2】:

将它们引入新的作用域将捕获它们的当前值:

(function(i, j) {
    td.click(function() {
        alert(i + ' ' + j);  // here I want to access to CURRENT i, j variables
    });
})(i, j);

【讨论】:

    【解决方案3】:

    您可以通过像这样在循环内执行函数来为 (i, j) 的“当前”值创建一个新范围

    td.click((function (i, j) {
        return function (event) {
            console.log(i, j);
        }
    })(i, j));
    

    您可以使用Function.prototype.bind 使其更简洁

    td.click(function(i, j, event){
      console.log(i, j);
    }.bind(td, i, j));
    

    注意这个.bind解决方案需要ECMAScript 5,所以如果你想支持旧版浏览器,请查看es5-shim


    看到这个demo

    【讨论】:

    • function hello() { return 'hi'; }
    • @naomik $scope.on("hi", function(){alert("LOL。你今天好吗?")});
    • @naomik 你真可爱 :D
    • 我也加了一个demo :)
    【解决方案4】:

    其他选项可以在元素中存储数据。

      for(var i = 0; i < 5; i++)
      {
          var tr = $('<tr></tr>');
          for (var j = 0; j < 5; j++) 
          {
              var td = $('<td></td>');
              this.data("position",{row:i, column:j});
    
              td.click(function() 
              {
                var position = this.data("position");
                alert(position.row + ' ' + position.column);  // here I want to access to CURRENT i, j variables
              })
    
              td.appendTo(tr);
          }
      } 
    

    【讨论】:

      【解决方案5】:

      我会将索引存储为属性并将单击处理程序添加到表中:

      var tableHtml = '';
      
      for(var i=0; i<5; i++) {
          tableHtml += '<tr>';
      
          for (var j=0; j<5; j++) {
              tableHtml += '<td data-i="' + i + '" data-j="' + j + '"></td>';
          }
      
          tableHtml += '</tr>';
      }
      
      $('table').append(tableHtml).on('click', 'td', function(ev) {
          var i = this.getAttribute('data-i'),
              j = this.getAttribute('data-j');
      });
      

      【讨论】:

      • 好主意,执行不力(恕我直言)。 jQuery 提供了非常好的方法来直接访问每个元素的数据,并且数据不需要出现在序列化的 HTML 表示中。
      • 是的。我很乐意使用 html5 的数据集,但它在 IE8 中不可用,这就是 jQuery 使用自定义 data() 的原因,以实现复古兼容性。数据属性是完全标准的,并与 HTML5 的数据集集成。 jQuery 的 data() 在删除元素时会留下一些污垢。或者它曾经......也许不再是了?
      • HTML5 data-XXX 属性和 jQuery 的 .data() 之间的唯一关联是前者的初始值被复制到后者中。除此之外没有任何联系。
      • 不是我的意思:数据集在旧版浏览器中不可用,因此 jQuery 使用它自己的自定义存储(我们通过 data() 访问)为每个浏览器提供类似的功能。
      • 我有时是个使用标准原生方法的疯子;)
      猜你喜欢
      • 2010-11-22
      • 1970-01-01
      • 1970-01-01
      • 2016-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-06
      相关资源
      最近更新 更多