Javascript-添加事件侦听器时未定义的数组元素

Javascript - undefined array element when adding eventlistener

本文关键字:未定义 数组元素 侦听器 添加 事件 Javascript-      更新时间:2023-09-26

我对javascript还很陌生,我正在尝试获取DOM中的所有"td"元素,并向它们添加一个点击事件。当代码执行完毕时,我可以看到cells数组中有37个元素,但当我单击该元素时,无论单击哪个元素,我都会在控制台语句中得到"clicked td37 undefined"。我不知道出了什么问题,如果有任何帮助,我将不胜感激。

<script>
window.addEventListener("DOMContentLoaded", createEventListeners, false);
function createEventListeners() {
   var cells = document.getElementsByTagName("td");
   console.log(cells);
   for (var i = 0; i < cells.length; i++) {
      cells[i].addEventListener("click", function () {
      console.log("clicked td" +  i + " " + cells[i]);
      }, false);
   }
 }
</script>

在循环结束时,i的值将是cells.length,因此cells[i]是未定义的。您需要将它们封装在一个函数中,以便i是您想要的值。阅读更多关于关闭这里

function createEventListeners() {
  var cells = document.getElementsByTagName("td");
  for (var i = 0; i < cells.length; i++) {
    (function(i) {
      cells[i].addEventListener("click", function () {
        console.log("clicked td" +  i + " " + cells[i]);
      }, false);
    }(i));
}

这是一个范围问题。你需要一个闭包。当循环中的任何Event被调用时,i都会查找它最后一个已知的值,这个值恰好是循环结束时的值。解决方案:

var pre = onload; // previous onload
onload = function(){
  if(pre)pre();
  function createEventListeners(){
    var cells = document.getElementsByTagName('td');
    for(var i=0,l=cells.length; i<l; i++){
      (function(i){
        cells[i].addEventListener('click', function(){
          console.log('i is at position:'+i));
        }, false);
      })(i);
    }
  }
  window.addEventListener('DOMContentLoaded', createEventListeners, false);
}

在循环结束时,i始终是您单击的任何对象的数组长度,由于它们是零索引的,因此不存在具有该索引的元素。例如,如果有10个元素,它们的索引为0-9,但当您单击其中任何一个元素时,i始终为10。

这个问答是关于何时以及如何使用闭包的一个很好的例子。由于这个问题是用jQuery标记的,因此each函数将是在jQuery中执行此操作的一种方法。当你使用each时,它可以很方便地关闭你正在学习的内容,所以这也可以:

$(document).ready(function () {
    var $tds = $('td');
    $tds.each(function (i, td) {
        $(td).click(function () {
            console.log(i, td);
        });
    });
});

此外,还有一种方法可以在不关闭的情况下做到这一点。如果您通过数据属性将迭代器的值存储到元素本身,它会存储值的副本,而不是引用,因此它会保留i在分配时的值:

window.addEventListener("DOMContentLoaded", createEventListeners, false);
function createEventListeners() {
    var cells = document.getElementsByTagName("td");
    console.log(cells);
    for (var i = 0; i < cells.length; i++) {
        cells[i].setAttribute('data-i', i);
        cells[i].addEventListener("click", function () {
            var i = this.getAttribute('data-i');
            console.log("clicked td" + i + " " + cells[i]);
        }, false);
    }
}