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

При нажатии на каждый div он должен предупреждать «1», если был нажат div 1, или «5», если был нажат div 2. Я попытался максимально упростить этот код, потому что он нужен в гораздо более крупном приложении.

<html>
<head>
<style type="text/css">
#div1 { background-color: #00ff00; margin: 10px; padding: 10px; }
#div2 { background-color: #0000ff; margin: 10px; padding: 10px; }
</style>
<script type="text/javascript">

function init()
{
  var total = 1;

  var div1 = document.getElementById('div1'),
      div2 = document.getElementById('div2');

  var helper = function(event, id)
  {
      if (event.stopPropagation) event.stopPropagation();
      if (event.preventDefault) event.preventDefault();

      alert('id='+id);
  }

  div1.addEventListener('click', function(event) { helper(event, total); }, false);

  total += 4;

  div2.addEventListener('click', function(event) { helper(event, total); }, false);

}

</script>
</head>

<body onload="init();">

<div id="div1">1</div>
<div id="div2">2</div>

</body>
</html>

Спасибо за вашу помощь! :-)


person Gary Green    schedule 22.11.2009    source источник


Ответы (2)


Проблема в том, что прослушиватели событий и total существуют в одной области (init ())

Функции событий всегда будут ссылаться на общее количество в области действия init (), даже если оно было изменено после объявления функций событий.

Чтобы обойти это, функции событий должны иметь «итог» в своей собственной области действия, который не изменится. Вы можете добавить еще один уровень области, используя анонимную функцию

Например:

(function (total) {
    div1.addEventListener('click', function(event) { helper(event, total); }, false);
}(total));

total += 4;

(function (total) {
  div2.addEventListener('click', function(event) { helper(event, total); }, false);
}(total));

Анонимным функциям передается текущее «общее» значение init () в качестве параметра. Это устанавливает другое «общее» значение для области действия анонимной функции, поэтому не имеет значения, изменится ли общее количество init () или нет, потому что функция события СНАЧАЛА будет ссылаться на область действия анонимной функции.

Изменить:

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

var helper = function(event, id)
{
  if (event.stopPropagation) event.stopPropagation();
  if (event.preventDefault) event.preventDefault();

  alert('id='+id);
};
person Matt    schedule 22.11.2009
comment
Ах. Так что фактически total становится похожей на указатель на переменную, во многом как в переменной C ++ *? - person Gary Green; 23.11.2009
comment
Фактически, это копируется в локальную область видимости. Если бы это был указатель, он бы изменился как внутри, так и за пределами области видимости, что вернуло бы вас к исходной проблеме. - person Matt; 23.11.2009
comment
Пример @Gary Matt верен, вот вам небольшая терминология. Вы столкнулись со своей конкретной проблемой из-за так называемого закрытия (jibbering.com/faq/ faq_notes / closures.html), который является отличной и мощной функцией JavaScript. Мэтт показал вам, как обойти свойство закрытия (которое, как вы видели, иногда мешает), используя анонимные функции и технику, известную как каррирование. См. ejohn.org/blog/partial-functions-in-javascript и stackoverflow.com/questions/1413916. - person Justin Johnson; 23.11.2009

Это почти то же самое, но, думаю, будет лучше:

div1.addEventListener('click', function(t){ return function(event) { helper(event, t); }}(total), false);

вместо:

(function (total) {
    div2.addEventListener('click', function(event) { helper(event, total); }, false);
}(total));
person m4roo    schedule 22.11.2009