Область переменной Javascript внутри цикла

Как мне поддерживать доступ к переменной i внутри цикла for for ниже? Я пытаюсь учиться, а не просто получить ответ, поэтому немного объяснений будет очень полезно. Спасибо!

var el, 
    len = statesPolyStrings.length;

for (var i = 0; i < len; i++) {
    el = document.getElementById(statesPolyStrings[i]);

    google.maps.event.addDomListener(el, 'mouseover', function() {
        $("#"+statesPolyStrings[i]).addClass("highlight");
        statesPolyObjects[i].setOptions({ strokeWeight: '2' });
    });
}

Ответ 1

Все ваши обратные вызовы используют одну и ту же переменную i.
Когда обработчик событий действительно запускается, i находится после конца массива.

Вам нужно обернуть тело цикла в функцию самозапускания, которая принимает i в качестве параметра.
Таким образом, каждая итерация получит свою собственную неизменную переменную i.

Например:

for (var i = 0; i < statesPolyStrings.length; i++) {
    (function(i) {
        ...
    })(i);
}

Ответ 2

Трюк с функциями для самостоятельного вызова отлично работает: он создает новую область (возможно, google для "scope в функциях javascript" ) и поэтому обрабатывает i как другую переменную и доставляет правильное значение функции обратного вызова слушателя событий.

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

И как вы все равно используете jQuery, тогда легко найти правильный индекс (ваш i) statesPolyObjects с помощью $.inArray() передача идентификатора вашего элемента и массива statesPolyStrings (при условии, что вы имеете дело с уникальными идентификаторами. Если нет, $("#"+statesPolyStrings[i]) также потерпит неудачу, так как он принимает первое, что он находит).

var el;

for (var i = 0, len = statesPolyStrings.length; i < len; i++) {
    el = document.getElementById(statesPolyStrings[i]);

    google.maps.event.addDomListener(el, 'mouseover', function(event) {
        $(this).addClass("highlight");
        statesPolyObjects[$.inArray(this.id, statesPolyStrings)].
            setOptions({ strokeWeight: '2' });
    });
}

Если вы все еще хотите придерживаться функции самозапускания, вы должны изменить следующую строку:

("#"+statesPolyStrings[i]).addClass("highlight");

к

$(this).addClass("highlight");

Если вы недостаточно знакомы с this и событиями, которые вы, возможно, захотите прочитать в этой статье: http://www.sitepoint.com/javascript-this-event-handlers/

Возможно, вы заметили, что я также написал аргумент event внутри функции анонимного обратного вызова. Попробуйте console.log это событие, которое вы получите бесплатно с помощью функции обратного вызова прослушивателя событий и изучите все другие вещи, к которым у вас есть доступ. Например, вы можете найти фактический элемент, на который вы нажали, с помощью event.target (поскольку фактическое наведение мыши могло произойти с дочерним элементом вашего элемента). Итак:

google.maps.event.addDomListener(el, 'mouseover', function(event) {
    console.log(event);
    ...

и откройте консоль вашего браузера, чтобы узнать, какое событие поставляет...

Помните, что google.maps.event.addDomListener передает что-то другое, чем document.body.addEventListener, а также разница между браузерами. Например, jQuery.on() также предоставляет некоторые вещи в объекте события, но там вы можете, по крайней мере, рассчитывать на одни и те же данные во всех браузерах.

Ответ 3

for (var i = 0; i < statesPolyStrings.length; i++) {
    (function(i){
        google.maps.event.addDomListener(document.getElementById(statesPolyStrings[i]), 'mouseover', function() {
        $("#"+statesPolyStrings[i]).addClass("highlight");
        statesPolyObjects[i].setOptions({ strokeWeight: '2' });
        });
    })(i)
}