Могу ли я передать «новую» анонимную функцию в addEventListener - PullRequest
1 голос
/ 10 декабря 2010

Я использую такой код для передачи аргументов в функции обработчика событий. Но в данном конкретном случае цикл вызывает проблемы. Только последняя ссылка Теги [i] доступна во всех активных визуальных вызовах. Это связано с тем, что анонимная функция, передающая аргумент, является одной и той же для всего цикла.

  for (var i = 0; i < linkTags.length; i++) {
    addCrossEvent(linkTags[i], "click", launchLink);
    addCrossEvent(linkTags[i], "mousedown", 
      function(evt) {
        activeVisual(evt, linkTags[i]);
      });
  }

Теперь я помню, как пытался добавить new перед объявлением анонимной функции, например:

  for (var i = 0; i < linkTags.length; i++) {
    addCrossEvent(linkTags[i], "click", launchLink);
    addCrossEvent(linkTags[i], "mousedown", 
      new function(evt) {
        activeVisual(evt, linkTags[i]);
      });
  }

Это не сработало. ActiveVisual никогда не вызывается. Может кто-нибудь объяснить мне, почему и как я могу заставить это работать, пожалуйста?

ОБНОВЛЕНИЕ ФИНАЛЬНОЕ РЕШЕНИЕ

Благодаря всем ответам ниже мой РАБОЧИЙ код теперь выглядит так:

  // Function that provides pass of event handling parameters with separate copy in each loop
  function callbackHandler(index) {
    return function(evt) {
      activeVisual(evt, linkTags[index]);
    }
  }
  ...
  for (var i = 0; i < linkTags.length; i++) {
    ...
    addCrossEvent(linkTags[i], "mousedown", callbackHandler(i));
  }

Ответы [ 2 ]

5 голосов
/ 10 декабря 2010

Вам нужно сделать это:

addCrossEvent(linkTags[i], "mousedown", 
      (function(i) {
          return function(evt) {
              activeVisual(evt, linkTags[i]);
          }
      )(i);
);

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

2 голосов
/ 10 декабря 2010

Для полноты, вот объяснение, почему ваш способ использования new не работает:

Когда вы вызываете функцию с new, функция генерирует пустой объект (который вы можете использовать с помощью this внутри функции и который наследует от прототипа функции) и возвращает его.
Таким образом, вы фактически не передаете функцию в качестве обработчика обратного вызова, но объект возвращается функцией.

Это не проблема, если объект реализует интерфейс EventListner для использования в качестве обработчика событий. Если вы сделаете это, вы можете использовать свой код с некоторыми изменениями:

  for (var i = 0; i < linkTags.length; i++) {
    addCrossEvent(linkTags[i], "click", launchLink);
    addCrossEvent(linkTags[i], "mousedown", 
      new (function(index) {
        this.handleEvent = function(evt) {
            activeVisual(evt, linkTags[index]);
        }
      })(i));
  }

Это на самом деле похоже на ответ @ Luca, потому что значение i фиксируется при создании объекта. Верхний код фактически идентичен:

function CallbackHandler(index) {
    this.handleEvent = function(evt) {
        activeVisual(evt, linkTags[index]);
    }
}

for (var i = 0; i < linkTags.length; i++) {
    addCrossEvent(linkTags[i], "click", launchLink);
    addCrossEvent(linkTags[i], "mousedown", new CallbackHandler(i));
}

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

Рабочая ДЕМО

...