2010-12-10 4 views
1

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

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

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

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 никогда не будет вызван. Может кто-нибудь объяснить мне, почему и как я могу заставить его работать, пожалуйста?

UPDATE окончательное решение

Благодаря все ответы ниже моего рабочего кода теперь выглядит следующим образом:

// 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)); 
    } 

ответ

5

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

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

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

+0

Если итератор я переменная является проблема как же это не вызывает проблем в этой линии addCrossEvent (linkTags [я], «клик», launchLink); ? Это только передается путем анонимности? –

+1

, потому что когда вы делаете addCrossEvent (linkTags [i], «click», launchLink); у вас есть значение i в массиве linkTags для каждого цикла, но когда функция вызывается в событии, у меня есть последнее значение, и вы получили только одну и ту же позицию в массиве – madeinstefano

+1

@ avok00: В 'addCrossEvent (linkTags [i ], «click», launchLink) 'вы передаете значение' linkTags [i] 'непосредственно в функцию.Но 'activeVisual (evt, linkTags [i]);' в * обратном вызове * вычисляется при вызове обратного вызова * * * в цикле. Но когда вызывается обратный вызов, цикл уже завершен, а 'i' имеет свое окончательное значение. –

2

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

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

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

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)); 
    } 

Это на самом деле похоже на @ ответ Люка, потому что значение 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)); 
} 

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

Working DEMO

+0

+1 Для очень хорошего решения и объяснения. Извините, что это не работает в IE8, может быть, это не понимает this.handleEvent :( –

+0

@ avok00: Может быть ... IE всегда немного особенный;) Но причиной может быть и то, что объект 'event' должен быть извлекается по-разному в IE. Для получения дополнительной информации об обработке событий и проблемах с перекрестным браузером читайте http://www.quirksmode.org/js/introevents.html. –

Смежные вопросы