Javascript: каждый обработчик событий, определенный в цикле for, одинаков, использует значения последней итерации - PullRequest
3 голосов
/ 28 мая 2011

У меня проблемы с пониманием правил области видимости в Javascript.

В следующем примере я бы предположил, что переменная url области видимости является закрытой в цикле for.И что функция onload-event увидит этот частный экземпляр

Но, похоже, что-то не работает - предупреждение будет всплывать с последним URL дважды.

Если кто-то сможет прояснить, что происходит, я буду благодарен.

<html>
<head>
</head>
<body>
<script type="text/javascript">
    var testArray = ["http://g0.gstatic.com/images/icons/onebox/weather_rain-40.png", "http://g0.gstatic.com/images/icons/onebox/weather_scatteredshowers-40.png"];
    for (var i=0;i<testArray.length;i++){
        var img = new Image();
        var url = testArray[i];
        img.onload = function(){
            alert(url);
        }
        img.src = url;
    }
</script>
</body>
</html>

Ответы [ 3 ]

7 голосов
/ 28 мая 2011

JavaScript не не имеет блок-область.

Единственный способ создать новую область видимости переменной - использовать функцию.

var testArray = ["http://g0.gstatic.com/images/icons/onebox/weather_rain-40.png", "http://g0.gstatic.com/images/icons/onebox/weather_scatteredshowers-40.png"];

function createImg( url ) {
    var img = new Image();

    img.onload = function(){
        alert(url);
    }
    img.src = url;
    return img;
}
for (var i=0;i<testArray.length;i++){
    var img = createImg(testArray[i]);
}

Передача testArray[i] в функцию, которая создает и возвращает новое изображение, гарантирует, что ссылка urlв обработчике onload будет тот, который был определен в функции.


РЕДАКТИРОВАТЬ:

В конечном счете, вы никогда не сделаете этого, если всевам нужен доступ к url.

. Вы просто получите его из свойства элемента через this.

function onloadHandler(){
    alert( this.src );  // <--- get the url from the .src property!
}

var testArray = ["http://g0.gstatic.com/images/icons/onebox/weather_rain-40.png", "http://g0.gstatic.com/images/icons/onebox/weather_scatteredshowers-40.png"];
for (var i=0;i<testArray.length;i++){
    var img = new Image();
    var url = testArray[i];
    img.onload = onloadHandler;
    img.src = url;
}

Таким образом, вы не создаетеидентичный экземпляр функции-обработчика в цикле, но совместно использующий тот же экземпляр и ссылающийся на элемент, получивший событие, через this.

4 голосов
/ 28 мая 2011

Javascript не является блок-областью, и поэтому требует новую функцию каждый раз, когда вы хотите новую область видимости. Смотрите ответ Патрика Ду.

Вот почему выгодно использовать [].map(function(x){...}) или [].forEach(function(x){...}), которые соответствуют стандарту javascript, так как вам все равно нужно будет определить эти функции.

var imageArray = urlArray.map(function(url) {
    var image = new Image();
    image.src = url;
    image.onload = function() {
        alert(url);
    };

    return image;
});
0 голосов
/ 28 мая 2011

Попробуйте это:)

var testArray = ["http://g0.gstatic.com/images/icons/onebox/weather_rain-40.png", "http://g0.gstatic.com/images/icons/onebox/weather_scatteredshowers-40.png"];
for (var i=0;i<testArray.length;i++){
    var img = new Image();
    var url = testArray[i];
    img.onload = function(){
        alert([img.src, url, i]);
    }
    img.src = url;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...