Создание элементов, а затем воспроизведение при щелчке по ячейкам таблицы


У меня есть HTML-таблица со многими ячейками, и я хочу дать каждой ячейке класс или идентификатор, чтобы можно было воспроизводить соответствующий звук. Поскольку ячеек много, я хочу автоматизировать эту задачу с помощью Javascript+jQuery и иметь менее загроможденный HTML.

Итак, предположим, что у меня есть ячейка с текстом a. Я хочу установить класс этой ячейки в click_sound_a и сгенерировать тег <audio> с идентификатором sound_a, который будет воспроизводить звук a.mp3. (Я также могу использовать идентификаторы для ячеек, но я думаю, что у меня будут некоторые дубликаты.)

У меня есть следующий код в качестве примера с 5 звуками:

<script type="text/Javascript">
 // trigger play event on an audio element
function playSound(sound) {
    $("#sound_"+sound).get(0).play();
}

$(document).ready(function() {
    var sounds = ["a", "i", "u", "e", "o"];

    // create HTML5 <audio> elements
    for (var i in sounds) {
        $("<audio id='sound_"+sounds[i]+"'>  <source src='/downloads/sounds/"+sounds[i]+".mp3' type='audio/mpeg'> </audio>").appendTo("#page");

        // make columns clickable to play sounds
        $(".click_sound_"+sounds[i]).click(function() {
            playSound(sounds[i]);
        });
    } // end for
});
</script>
Проблема заключается в том, что когда цикл завершается, все ячейки получают звук последнего элемента, даже если им был присвоен правильный класс. Так что в этом случае каждая клетка будет играть o.mp3. Где жучок?
1 2

1 ответ:

<script type="text/Javascript">
 // trigger play event on an audio element
function playSound(sound) {
  return function() {
    $("#sound_"+sound).get(0).play();
  }
}

$(document).ready(function() {
    var sounds = ["a", "i", "u", "e", "o"];

    // create HTML5 <audio> elements
    for (var i in sounds) {
        $("<audio id='sound_"+sounds[i]+"'>  <source src='/downloads/sounds/"+sounds[i]+".mp3' type='audio/mpeg'> </audio>").appendTo("#page");

        // make columns clickable to play sounds
        $(".click_sound_"+sounds[i]).click(playSound(sounds[i]));
    } // end for
});
</script>

Пояснение: это типичный gotcha JavaScript. Всякий раз, когда вызывается определенный вами обработчик событий, он ищет значение переменной i, которая в последний раз была обновлена с помощью 4. Для привязки соответствующего значения к обработчику событий необходимо использовать замыкание.

На самом деле это почти тот же пример, что и в книге Крокфорда: закрытие в хороших частях