Javascript только устанавливает атрибут для последнего элемента в массиве - PullRequest
1 голос
/ 10 августа 2011

У меня есть массив из ~ 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 ]

6 голосов
/ 10 августа 2011

Это классическая проблема с асинхронным обратным вызовом в Javascript. Обработчик onload будет вызван через некоторое время, еще долго после завершения цикла for, поэтому индекс цикла for будет помечен в конце, где он завершился, и локальные переменные newImg и coName будут иметь только свои последние значения в цикле. .

Любые переменные, которые вы хотите использовать в обработчике загрузки, должны быть переданы в фактическое закрытие функции, чтобы они были уникально доступны для каждого отдельного обработчика загрузки. Есть несколько способов сделать это.

Этот способ использует закрытие функции для захвата переданного значения и делает его доступным для обработчика функции загрузки:

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. Эта функция возвращает другую анонимную функцию, которая назначается в качестве обработчика загрузки. Но из-за того, как замыкания функций работают в javascript, значение coName фиксируется в замыкании функций и остается доступным для обработчика загрузки во время закрытия функции. Можно немного подумать об этом как об экземпляре функции с состоянием вокруг нее (значения локальных переменных), которая уникально захватывает каждый раз, когда она устанавливается. В этом случае он захватывает значение переменной coName и помещает его в замыкание, где оно становится уникальным и не будет затронуто последующими изменениями внешней переменной coName, которая находится в цикле for.

Другой способ сделать это - поместить параметр в реальный объект, чтобы вы могли получить его оттуда:

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

    };
}
0 голосов
/ 10 августа 2011

Проблема в том, что переменная 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...