[英]Javascript - undefined array element when adding eventlistener
I am fairly new to javascript and I am trying to grab all the "td" elements in the DOM and add a click event to them. 我是javascript的新手,我试图抓住DOM中的所有“td”元素并向它们添加一个click事件。 When the code finishes executing, i can see I have 37 elements in cells array, but when I click the element, I get "clicked td37 undefined" in my console statement no matter which element is clicked.
当代码完成执行时,我可以看到我在单元格数组中有37个元素,但是当我单击该元素时,无论点击哪个元素,我都会在控制台语句中“点击td37 undefined”。 I do not have a clue what is wrong and any help would be appreciated.
我不知道什么是错的,任何帮助将不胜感激。
<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>
At the end of the loop, the value of i
will be the cells.length
, so cells[i]
is undefined. 在循环结束时,
i
的值将是cells.length
,因此cells[i]
是未定义的。 You need to wrap them in a function so that i
is the value you want. 你需要将它们包装在一个函数中,这样
i
就是你想要的值。 Read more about closure here 阅读更多关于闭包的信息
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));
}
This is a scope issue. 这是一个范围问题。 You need a closure.
你需要一个关闭。 By the time any
Event
in your loop is called, i
looks for it's last know value, which happens to be it's value at the end of the loop. 当你的循环中的任何
Event
被调用时, i
查找它的最后一个已知值,这恰好是它在循环结束时的值。 Solution: 解:
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);
}
At the end of your loop, i
is always the length of the array for anything you click on and since they're zero indexed, no element with that index exists. 在循环结束时,对于您点击的任何内容,
i
总是数组的长度,因为它们是零索引的,所以不存在具有该索引的元素。 For example, if there are 10 elements, they're indexed as 0-9, but when you click any of them, i
is always 10. 例如,如果有10个元素,则它们被索引为0-9,但是当您单击其中任何一个时,
i
总是10。
This question+answers are a great example of when and how to use closures. 这个问题+答案是何时以及如何使用闭包的一个很好的例子。 Since this question is tagged with
jQuery
, the each
function would be a way to do it in jQuery
. 由于这个问题是标记
jQuery
中, each
功能将是一个办法做到这一点的jQuery
。 When you use each
, it conveniently closes over what you are eaching through, so this would also work: 当你使用
each
,它可以方便地关闭你正在经历的东西,所以这也可以工作:
$(document).ready(function () {
var $tds = $('td');
$tds.each(function (i, td) {
$(td).click(function () {
console.log(i, td);
});
});
});
And also, there is a way to do it without closures. 而且,有一种方法可以在没有闭包的情况下完成。 If you store the value of the iterator onto the element itself via a data attribute, it stores a copy of the value, rather than a reference, so it retains the value of
i
at the time it was assigned: 如果通过数据属性将迭代器的值存储到元素本身,它会存储值的副本而不是引用,因此它在分配时保留
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);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.