Javascript 仅设置数组中最后一项的属性
我有一个约 50 个项目的数组,在 javascript 中,它通过这个数组来检查一个条件,如果满足条件,它会为要检查的复选框设置属性.它通过得很好,但每次只更改数组中的最后一项.这是一段代码.
I have an array of ~50 items and in javascript it goes through this array to check a condition and if the condition is met it setsattribute for checkboxes on the be checked. It goes through nicely but only changes the very final item in the array every time. Here is a section of the code.
for (i = 0; i < urlArray.length; i++) {
var newImg = new Image();
var coName = companyArray[i];
newImg.onload = function(){
if (condition is met){
nStar++;
document.getElementById(coName).setAttribute("checked", "checked");
document.getElementById(coName).checked = true;
} else {
nStar++;
document.getElementById(coName).setAttribute("checked", "checked");
document.getElementById(coName).checked = true;
document.getElementById(coName).setAttribute("disabled", "disabled");
document.getElementById(coName).disabled = true;
}
};
所以你可以看到条件是否满足,它仍然会改变属性,但我收到的错误是它只改变了数组中的最后一项.有什么想法吗?
So as you can see if the condition is met or not it will still change the attributes but the error I have been receiving is that it only changes the final item in the array. Any ideas?
推荐答案
这是 Javascript 中异步回调的经典问题.onload 处理程序将在一段时间后调用,在 for 循环完成很久之后,因此 for 循环中的索引被固定在它结束的末尾,并且局部变量 newImg 和 coName 将只有它们在循环中的最后一个值.
This is a classic issue with an asynchronous callback in Javascript. The onload handler will be called some time later, long after the for loop has finished, thus the index in the for loop is pegged at the end where it ended up and the local variables newImg and coName will only have their last values in the loop.
您希望在 onload 处理程序中使用的任何变量都必须传递到实际的函数闭包中,以便它们对每个不同的 onload 处理程序都是唯一可用的.有几种方法可以做到这一点.
Any variables that you wish to use inside the onload handler will have to passed into the actual function closure so that they are uniquely available for each different onload handler. There are several ways to do that.
这种方式使用函数闭包来捕获传入的值并使其可用于 onload 函数处理程序:
This way uses a function closure to capture the passed in value and make it available to the onload function handler:
for (i = 0; i < urlArray.length; i++) {
var newImg = new Image();
var coName = companyArray[i];
newImg.onload = (function (coName) {
return function(){
if (condition is met){
nStar++;
document.getElementById(coName).setAttribute("checked", "checked");
document.getElementById(coName).checked = true;
} else {
nStar++;
document.getElementById(coName).setAttribute("checked", "checked");
document.getElementById(coName).checked = true;
document.getElementById(coName).setAttribute("disabled", "disabled");
document.getElementById(coName).disabled = true;
}
};
}) (coName);
}
在 Javascript 语言中,此方法的作用是将执行匿名函数调用的返回值分配给 onload 属性.该匿名函数调用将 coName 参数传递给它.该函数返回另一个匿名函数,该函数被分配为 onload 处理程序.但是,由于函数闭包在 javascript 中的工作方式,coName 的值被捕获在函数闭包中,并且在函数闭包期间保持可供 onload 处理程序访问.可以把它想象成一个函数的实例,它周围有状态(局部变量的值),每次设置时都会被唯一地捕获.在这种情况下,它会捕获 coName 变量的值并将其放入闭包中,在该闭包中它变得唯一,并且不会受到后续对 for 循环中外部 coName 变量的更改的影响.
In Javascript-speak, what this method does is assign to the onload attribute the return value from executing an anonymous function call. That anonymous function call passed the coName parameter into it. That function returns another anonymous function which is what gets assigned as the onload handler. But, because of the way function closures work in javascript, the value of coName is captured in the function closure and is kept accessible to the onload handler for the duration of the function closure. One can think of it a little like an instance of a function with state around it (values of local variables) that is uniquely capture each time it's set up. In this case, it captures the value of the coName variable and puts it into the closure where it becomes unique and won't be effected by later changes to the outer coName variable that's in the for loop.
另一种方法是将参数放在实际对象上,以便您可以从那里检索它:
Another way to do it is to put the parameter on the actual object so you can retrieve it from there:
for (i = 0; i < urlArray.length; i++) {
var newImg = new Image();
newImg.setAttribute("coName". companyArray[i]);
newImg.onload = function() {
var coName = this.getAttribute("coName");
if (condition is met){
nStar++;
document.getElementById(coName).setAttribute("checked", "checked");
document.getElementById(coName).checked = true;
} else {
nStar++;
document.getElementById(coName).setAttribute("checked", "checked");
document.getElementById(coName).checked = true;
document.getElementById(coName).setAttribute("disabled", "disabled");
document.getElementById(coName).disabled = true;
}
};
}
相关文章