#javascript #scope
#javascript #область действия
Вопрос:
У меня проблемы с пониманием правил области видимости в Javascript.
В приведенном ниже примере я бы предположил, что переменная url области видимости является частной в for-loop. И что функция 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>
Ответ №1:
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
.
Комментарии:
1. 1 Специально для перемещения определения функции из цикла.
2. Вот почему выгодно использовать
[].map(function(x){...})
or[].forEach(function(x){...})
, которые есть в стандарте javascript, поскольку вам все равно нужно будет определить эти функции.
Ответ №2:
Javascript не ограничен блоками и, следовательно, требует новой функции каждый раз, когда вам нужна новая область видимости. Смотрите ответ Патрика ду.
Вот почему выгодно использовать [].map(function(x){...})
or [].forEach(function(x){...})
, которые есть в стандарте javascript, поскольку вам все равно нужно будет определить эти функции.
var imageArray = urlArray.map(function(url) {
var image = new Image();
image.src = url;
image.onload = function() {
alert(url);
};
return image;
});
Комментарии:
1. 1 для
.map()
и.forEach()
, хотя вам нужно было бы добавить для них поддержку в IE9.2. Поддержка IE9 ниже может быть решена с помощью прокладки .
Ответ №3:
Попробуйте это 🙂
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;
}