Динамическое изменение события HTML DOM

Я пытаюсь динамически изменить событие onClick элемента, и у меня есть что-то вроде следующего:

for (var i = 1; i < 5; i++)
{
    getElementById('element' + i).onclick = function() { existingFunction(i); return false; };
}

Кажется, все работает нормально, за исключением того факта, что аргумент, переданный в 'existingFunction ()', является окончательным значением i = 4 каждый раз, когда он вызывается. Есть ли способ привязать функцию к onclick, которая использует значение i во время привязки, а не то, что она, кажется, делает в данный момент, и ссылается на исходный i в цикле for.

Также есть ли способ выполнить одну и ту же привязку без необходимости каждый раз создавать анонимные функции? чтобы я мог напрямую ссылаться на 'existingFunction' в каждом onclick по соображениям производительности?

Ура, ребята, Ён


person yogibear    schedule 17.11.2009    source источник


Ответы (4)


Изменять

for (var i = 1; i < 5; i++)
{
    getElementById('element' + i).onclick = function() { existingFunction(i); return false; };
}

to

for (var i = 1; i < 5; i++)
{
    getElementById('element' + i).onclick = createOneHandler(i);
}

function createOneHandler(number){  
    return function() {  
        existingFunction(number); 
    }  
}

и он должен работать нормально.

Рабочая демонстрация

Здесь дано хорошее объяснение

JavaScript, время проверять закрытие

person rahul    schedule 17.11.2009
comment
Ха-ха, на странице, на которую вы ссылались, почти такая же ситуация. Я прочитал статью, и за это мне тоже очень помогли. - person yogibear; 17.11.2009

поскольку i всегда равно 4, у вас проблема с определением объема, я советую прочитать это. Определение объема - это действительно важное понятие, поэтому вам лучше понять, что происходит.

лучший код был бы

for (var i = 1; i < 5; i++)
{
    getElementById('element' + i).onclick = existingFunction;
}

onclick передаст событие, имеющее аргумент, чтобы вы могли знать, какой элемент был нажат, т.е.

function existingFunction(event){
  // DO something here
}

вы можете узнать больше о событиях здесь. IE имеет ту же модель событий, что и другой браузер, поэтому вам придется с ней справиться.

И последнее: я советую вам использовать JS-фреймворк (JQuery, ExtJS, DOJO, Prototype ...), потому что это упростит вашу задачу.

person RageZ    schedule 17.11.2009

опубликованный вами код должен работать так, как вы планировали, ваша проблема с i = 4 в другом месте. edit: это неправильно, rageZ прав в отношении проблемы с масштабом.

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

var f = function (i) { return function () { existingFunction(i); return false; } }
for (...) { document.getElementById(...).onclick = f(i); }

Кстати, вы должны использовать что-то вроде jQuery для манипуляции с DOM (краткий синтаксис) и, возможно, Zeta (http://codex.sigpipe.cz/zeta/) для композиции функций

var f = compose(false_, existingFunction);
for (...) { $(...).click(f(i));
person just somebody    schedule 17.11.2009

Ура! Это снова замыкание петли! См. 422784, 643542, 1552941 и др. для дальнейшего обсуждения.

есть ли способ выполнить одно и то же связывание без необходимости каждый раз создавать анонимные функции?

Да, в ECMAScript Fifth Edition вы получаете function.bind:

for (var i = 1; i < 5; i++)
    document.getElementById('element'+i).onclick= existingFunction.bind(window, i);

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

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

person bobince    schedule 17.11.2009