Подтвердить что ты не робот

Доступ к внешней переменной в цикле от закрытия Javascript

См:

for (var i in this.items) {
    var item = this.items[i];
    $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>");
    $("#showcasebutton_"+item.id).click(function() {
        alert(item.id);
        self.switchto(item.id);
    });
}

Проблема в том, что alerted item.id всегда является идентификатором последнего элемента массива (this.items). Как решить?

4b9b3361

Ответ 1

Проблема, которую вы здесь имеете, состоит в том, что переменная item изменяется с каждым циклом. Когда вы ссылаетесь на item в какой-то более поздний момент, используется последнее значение, которое оно удерживает. Вы можете использовать технику, называемую closure (по существу функцию, возвращающую функцию), чтобы быстро развернуть эту переменную.

    for (var i in this.items) {
            var item = this.items[i];
            $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>");
            $("#showcasebutton_"+item.id).click( 
                // create an anonymous function that will scope "item"
                (function(item) {
                   // that returns our function 
                   return function() {
                    alert(item.id);
                    self.switchto(item.id);
                   };
                })(item) // immediately call it with "item"
            );
    }

Боковое примечание. Я вижу, что у вас есть jQuery. Он имеет вспомогательную функцию $.each(), которая может использоваться с массивами и может быть ярлыком для простых для/каждого цикла. Из-за того, как работает обследование в этом вызове, вам не нужно использовать закрытие, потому что "элемент" уже является параметром функции, когда он был вызван, а не хранится в var в области родительской функции, как и правда в вашем примере.

$.each(this.items,function(i, item) {
  $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>");
  $("#showcasebutton_"+item.id).click(function() {
    alert(item.id);
    self.switchto(item.id);
  });
});

Ответ 2

Другой способ подойти к этому - убедиться, что бизнес = items[i] эффективно выполняется путем вызова функции. В сокращении это:

for (var i in this.items) {
    (function(item) {
        $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>");
        $("#showcasebutton_"+item.id).click(function() {
            alert(item.id);
            self.switchto(item.id);
        });
    })(this.items[i]);
}

Анонимная функция немного беспорядочна, поэтому для нее предпочтительнее иметь не-анонимную цель, но она делает трюк.

Ответ 3

Закрытие Javascript хранит ссылки на их переменные, поэтому все обработчики onclick используют одну и ту же переменную.

Вам нужно записать переменную в промежуточную функцию, например:

function buildClickHandler(pageNumber) {
    return function()  {    //Create and return a new function
        alert(item.id);
        self.switchto(item.id);
    }
}

Затем используйте эту функцию для создания обработчиков click, например:

for (var i in this.items) {
    var item = this.items[i];
    $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>");

    $("#showcasebutton_"+item.id).click(buildClickHandler(item));
}

Каждый вызов buildClickHandler создает отдельное закрытие с собственной переменной.

Ответ 4

попробуйте этот цикл

for (var i=0; i < this.items.length; i++) {
  this.items[i]
};

Ответ 5

Я очень хорошо знаю, что это старый пост, но похоже, что гениальные люди, проектирующие jQuery (которые, как я полагал, вы должны использовать), сделали наиболее оптимальное решение вашей проблемы, насколько я понимаю.

В новой версии 1.4 версии библиотеки они добавили функцию jQuery.proxy(). Это позволяет вам эффективно изменять контекст/область действия функции, которую вы вызываете, - выполнил путь jQuery, который гарантирует, что вы можете прекратить использование техник, которые могли бы испортить вещи.