Javascript仅为数组中的最后一项设置属性

时间:2011-08-10 00:26:13

标签: javascript arrays attributes checkbox

我有一个约50项的数组,在javascript中它通过这个数组来检查一个条件,如果满足条件,它就会为要检查的复选框设置属性。它很顺利,但每次只更改数组中的最后一项。这是代码的一部分。

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;        
        }

    };

因此,您可以看到是否满足条件,它仍然会更改属性,但我收到的错误是它只更改数组中的最后一项。有什么想法吗?

2 个答案:

答案 0 :(得分:6)

这是Javascript中异步回调的经典问题。 onload处理程序将在for循环结束很久之后的某个时间被调用,因此for循环中的索引在结束时挂起,而局部变量newImg和coName只在循环中有它们的最后一个值

您希望在onload处理程序中使用的任何变量都必须传递到实际的函数闭包中,以便它们对于每个不同的onload处理程序都是唯一可用的。有几种方法可以做到这一点。

这种方式使用函数闭包来捕获传入的值并使其可用于onload函数处理程序:

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变量的后续更改的影响。

另一种方法是将参数放在实际对象上,以便从那里检索它:

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;        
        }

    };
}

答案 1 :(得分:0)

问题是变量coName将始终是执行任何函数时的最后一个数组值。你可以这样做:

for (i = 0; i < urlArray.length; i++) {
    var newImg = new Image();
    var coName = companyArray[i];
    newImg.onload = (function(name){
        return function(){
            if (true) {
                nStar++;
                document.getElementById(name).setAttribute("checked", "checked");
                document.getElementById(name).checked = true;
            } else {
                nStar++;

                document.getElementById(name).setAttribute("checked", "checked");
                document.getElementById(name).checked = true;
                document.getElementById(name).setAttribute("disabled", "disabled");
                document.getElementById(name).disabled = true;
            }
        }
    })(coName);
}