Анонимная функция событий Javascript в Firefox

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

document.getElementById(
    "course"+displayed_year_index+occurrences_indices[displayed_year_index]).onclick =
        eval("function() {PrintReceipt("+result.years[result_year_index].rul_code+");};");

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

Достаточно сказать, что это работает абсолютно нормально в Firefox 2. Но Firefox 3 выдает «Синтаксическую ошибку», указывая в квадратных скобках после слова «функция».

У кого-нибудь есть умные идеи о том, как я могу это исправить?


Просто чтобы было совершенно ясно, что я пытаюсь сделать, вот очень упрощенный пример:

for (index=0; index<4; index++) {
    document.getElementById("div"+index).onclick = 
        eval("function () {Foo(index);};");
}

Другими словами, я хочу запускать одну и ту же функцию с другим значением параметра для каждого div.


person Community    schedule 17.11.2008    source источник


Ответы (4)


ИМХО замыкания в этом случае использовать не стоит и не нужно создавать новую функцию для каждого онлика (использует намного больше памяти, чем нужно) и eval — неправильный ответ.

Вы знаете, что элемент, который вы получаете с помощью getElementById, является объектом и что вы можете присваивать ему значения?

for ( /* your definition */ ) {
  var e = document.getElementById(
    "course"+displayed_year_index+occurrences_indices[displayed_year_index]
  );
  e.rul_code = result.years[result_year_index].rul_code;
  e.onclick = PrintReceipt;
}

Но сначала вы должны определить PrintReceipt:

function PrintReceipt() {
  //This function is called as an onclick handler, and "this" is a reference to the element that was clicked.
  if (this.rul_code === undefined) { return; }
  //Do what you want with this.rul_code
  alert (this.rul_code);
}
person some    schedule 17.11.2008
comment
Вы, конечно, полностью правы. Никогда не используйте кувалду, чтобы расколоть орех, а? - person Guillermo Phillips; 18.11.2008
comment
Спасибо за это. Я рвал на себе волосы, пытаясь понять ответ! - person Matt Ellen; 19.11.2009

Вы пробовали что-то подобное?

document.getElementById('course' + displayed_year_index + occurences_indices[displayed_year_index]) =
    function (nr)
    {
        return function () { PrintReceipt(nr) }
    } (result.years[result_year_index].rul_code);

Не могли бы вы опубликовать цикл, чтобы помочь нам найти проблему, а не заставлять нас гадать, что вы пытаетесь сделать?

person Tom    schedule 17.11.2008
comment
Хороший ответ, но ссылка на хорошее объяснение замыканий очень поможет. Я понимаю ваш код, но он все еще пугает меня;) У того, кто не знает, что такое замыкание, не будет шанса. К сожалению, я еще не видел четкого и краткого объяснения замыканий нигде в Интернете :( - person Gareth; 17.11.2008
comment
К сожалению, мне нужно назначить событие onclick, и из-за этого я не могу передать параметр анонимной функции. - person Guillermo Phillips; 17.11.2008

Используйте замыкания, как предложил Том.

Вот хорошее объяснение Джона Резига: Как работают замыкания (pdf)

person orip    schedule 17.11.2008

Кажется, это направление, в котором вы хотели бы двигаться:

document.getElementById("course"+displayed_year_index+occurrences_indices[displayed_year_index]).addeventlistener("click",  function() {
    var current_rul_code = result.years[result_year_index].rul_code;
    PrintReceipt(current_rul_code);
}, true);

Это должно привести к тому, что каждое событие onclick будет создано в другой области (каждая итерация цикла). Замыкания позаботятся обо всем остальном.

person ng.mangine    schedule 17.11.2008
comment
Это не работает, потому что параметр PrintReceipt должен быть константой при вызове onclick. - person Guillermo Phillips; 17.11.2008
comment
Это не должно быть константой, потому что функция будет вызываться в исходной области при возникновении события. - person ng.mangine; 17.11.2008
comment
Спасибо, я попробовал ваш пример, как указано, но он не работает. Это связано с тем, что result.years[result_year_index].rul_code не находится в области видимости, когда функция вызывается из onClick. Что мне действительно нужно, так это значение переменной (в данном случае 13208), которое будет передано функции. - person Guillermo Phillips; 17.11.2008