Странные вещи в JavaScript “для”

Я использую jQuery, и у меня есть странная вещь, которую я не понимаю. У меня есть некоторый код:

for (i = 1; i <= some_number; i++) {
    $("#some_button" + i).click(function() {
        alert(i);
    });
}

"#some_button" как имя говорит - они - некоторые кнопки. При нажатии они должны открыть поле с, он - число, корректное? Но они не делают. Если существует 4 кнопки, они всегда раскрываются "5" (количество кнопок + 1). Почему то, что так?

8
задан Anurag 30 June 2010 в 15:47
поделиться

6 ответов

Это связано с областью видимости JavaScript. Вы можете легко обойти это, введя другую область видимости, добавив функцию и заставив эту функцию вызывать себя и передавать i:

for (var i = 1; i <= some_number; i++) {
  (function(j) {
    $("#some_button" + j).click(function() {
      alert(j);
    });
  })(i);
}

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

РЕДАКТИРОВАТЬ: RE: Самовызывающиеся функции: Самовызывающая функция - это функция, которая вызывает себя анонимно. Вы не создаете его экземпляр и не присваиваете его переменной. Он принимает следующую форму (обратите внимание на открывающие скобки):

(function(args) {
  // function body that might modify args
})(args_to_pass_in);

В отношении этого вопроса тело анонимной функции будет иметь следующий вид:

$("#some_button" + j).click(function() {
  alert(j);
});

Объединив их вместе, мы получим ответ в первом блоке кода. Функция анонимного самовызова ожидает аргумент с именем j . Он ищет любой элемент с идентификатором some_button с целочисленным значением j в конце (например, some_button1, some_button10). Каждый раз, когда щелкают по одному из этих элементов, отображается значение j . Предпоследняя строка решения передает значение i , которое является счетчиком цикла, в котором вызывается анонимная функция самовызова. Если сделать по-другому, это может выглядеть так:

var innerFunction = function(j) {
  $("#some_button" + j).click(function() {
    alert(j);
  });
};

for (var i = 1; i <= some_number; i++) {
  innerFunction(i);
}
18
ответ дан 5 December 2019 в 06:09
поделиться

У вас очень распространенная проблема с замыканием в цикле for.

Переменные, заключенные в замыкание, имеют общее единое окружение, поэтому к моменту вызова обратного вызова click цикл уже завершится, а переменная i будет указывать на последнюю запись.

Это можно решить с помощью еще большего количества замыканий, используя фабрику функций:

function makeOnClickCallback(i) {  
   return function() {  
      alert(i);
   };  
} 

var i;

for (i = 0; i < some_number; i++) {
    $("#some_button" + i).click(makeOnClickCallback(i));
}

Это может быть довольно сложной темой, если вы не знакомы с тем, как работают замыкания. Вы можете ознакомиться со следующей статьей Mozilla для краткого введения:

9
ответ дан 5 December 2019 в 06:09
поделиться

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

Существуют различные способы обойти это (когда такое поведение не является тем, чего вы хотите). Один из них (если у вас простая функция, как здесь) - использовать конструктор Function вместо литерала функции:

$("#some_button" + i).click(new Function("alert("+i+")");
0
ответ дан 5 December 2019 в 06:09
поделиться
  (function (some_number) {
    for (i = 1; i <= some_number; i++) {
      $("#some_button" + i).click(function() {
        alert(i);
      });
    }
  })(some_number);

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

-1
ответ дан 5 December 2019 в 06:09
поделиться

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

Возможно, я бы прикрепил ко всем кнопкам одну и ту же функцию, которая получила бы кнопку из события, отделила бы "some_button" от ID и оповестила бы о результате. Это не так красиво, но я гарантирую, что каждый в офисе сможет проследить за этим с первого взгляда.

-1
ответ дан 5 December 2019 в 06:09
поделиться

Потому что в тот момент, когда вы нажимаете на них, i == 5.

2
ответ дан 5 December 2019 в 06:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: