为什么循环将最后一个索引元素的引用分配给? [英] Why is the loop assigning a reference of the last index element to?
问题描述
我想为我的所有标签添加一个事件侦听器,每个标签都传递一个对自身的引用作为事件触发时的参数.这是我写的函数:
I want to add an event listener to all of my tags, each passing a reference to itself as a parameter when the even is triggered. Here is the function I wrote:
function validateDigitsFeature()
{
// Add the event listeners to input tags
// Get the array of input tags
var inputTags = document.getElementsByClassName('validateInput');
var tagId;
// Loop through them, adding the onkeypress event listener to each one
for (var i = 0; i < inputTags.length; i++)
{
// Give each input element an id
tagId = inputTags[i].id = 'input_id_' + i;
inputTags[i].addEventListener('keyup', function(){isNumberOrDot(event, tagId);}, false);
}
}
基本上该函数应执行以下操作:
Basically the function should do the following:
- 将具有指定类名的所有输入标签存储在一个数组中
- 循环遍历数组,为每个标签添加一个 id 和
- 使用
isNumberOrDot(event, tagId)
处理程序添加onkeyup
事件侦听器.
- Store all the input tags with the specified classname in an array
- Loop through the array, adding an id to each tag and
- Adding the
onkeyup
event listener with theisNumberOrDot(event, tagId)
handler.
问题
添加了 onkeyup 事件,但每个事件的处理程序总是引用数组最后一个元素的 tagId
.
Problem
The onkeyup event is added, but they handlers of each one is always referencing the tagId
of the last element of the array.
代码/逻辑有什么问题?以及如何修复?
What is wrong with the code/logic? And how can it be fixed?
当然,这个问题与循环中的 JavaScript 闭包有关,虽然这个问题可以有更一般的答案,但它特定于正在使用的事件侦听器.对于更高级的开发人员,可能很容易将通用解决方案应用于此问题.但对我来说,其他解决方案仍然没有提供完整的解释,甚至没有奏效.
Sure this problem is related to JavaScript Closure in loops, while this question could have a more general answer, it is specific to event listeners being used. To more advanced developers, it might be easy to apply the general solution to this problem. But to me the other solutions still didn't provide a full explanation or even worked.
提前致谢.
推荐答案
因为实际事件发生在 for
循环已经完成运行之后的某个时间,因此它的索引是最后一个值并且您函数中的任何局部变量(如 tagId
)也处于其最后一个值.您需要创建某种闭包,为每个事件处理程序唯一地保留 i
或 tagId
的值,以便它们每个都可以访问自己的值.
Because the actual event occurs sometime in the future after your for
loop has already finished running and thus its index is at the last value and any local variables in your function like tagId
are also at their last value. You need to create some sort of closure that preserves the value of i
or tagId
uniquely for each event handler so they each have access to their own value.
有几种不同的方法可以做到这一点,但都涉及将 i
值传递给每个事件处理程序的函数.
There are several different ways to do that, but all involve passing the i
value to a function for each event handler.
这是使用 IIFE(立即调用的函数表达式)的一个:
Here's one using an IIFE (immediately invoked function expression):
function validateDigitsFeature()
{
// Add the event listeners to input tags
// Get the array of input tags
var inputTags = document.getElementsByClassName('validateInput');
// Loop through them, adding the onkeypress event listener to each one
for (var i = 0; i < inputTags.length; i++)
{
// Give each input element an id
(function() {
// creates a unique function context for each event handler so the
// value of tagId is unique for each event handler
var tagId = inputTags[i].id = 'input_id_' + i;
inputTags[i].addEventListener('keyup', function(){isNumberOrDot(event, tagId);}, false);
})();
}
}
一种更常见的方法是将 for
循环中的索引传递到闭包中,并在事件处理程序中基于它进行任何计算(尽管任一方法都可以正常工作),如下所示:
A little more common way to do this is to pass the index from the for
loop into the closure and do any calculation based on it inside the event handler (though either method works fine) like this:
function validateDigitsFeature()
{
// Add the event listeners to input tags
// Get the array of input tags
var inputTags = document.getElementsByClassName('validateInput');
// Loop through them, adding the onkeypress event listener to each one
for (var i = 0; i < inputTags.length; i++)
{
// Give each input element an id
(function(index) {
// passes the `for` loop index into a function closure
// so it is uniquely preserved for each event handler
inputTags[index].addEventListener('keyup', function(){
isNumberOrDot(event, inputTags[index].id = 'input_id_' + index);
}, false);
})(i);
}
}
这篇关于为什么循环将最后一个索引元素的引用分配给?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!