Обхват на променлива на 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())

Функциите за събития винаги ще препращат към total в рамките на обхвата на 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() като параметър. Това задава друг 'total' към обхвата на анонимната функция, така че няма значение дали общата стойност на init() се променя или не, тъй като функцията за събитие ПЪРВО ще се позовава на обхвата на анонимната функция.

Редактиране:

Освен това трябва да поставите точка и запетая след затварящата фигурна скоба на помощната функция, в противен случай скриптът ще се оплаче, че 'event' е недефинирано.

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