Установка onclick для использования текущего значения переменной в цикле

Название может не иметь смысла, да и описание само по себе не имеет смысла, поэтому вот пример кода:

for(var a=0;a<10;a++) {
    var b=document.createElement('b')
    b.onclick=function() {
        alert(a)
    }
    b.innerHTML=a
    document.body.appendChild(b)
}

Странно то, что когда я устанавливаю innerHTML в a, он использует текущее значение a. Итак, этот код создает десять <b> элементы со значениями 0, 1, 2, 3, 4, 5, 6, 7, 8 и 9. Это отлично работает. Что не является, однако, функцией onclick. Возвращает окончательное значение a (10) при нажатии любого из этих элементов. Я попытался установить другую переменную в a а затем с помощью этой другой переменной в событии onclick, но все равно он возвращает окончательное значение a, Как бы я использовал это значение a когда онклик установлен?

2 ответа

Решение

Попробуйте следующее

b.onclick= function(arg) {
    return function() {
        alert(arg);
    }
}(a);

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

Решение обходит это, создавая новую функцию и значение для каждой области, а затем немедленно устанавливая это значение на текущее значение a,

Вот версия, которая немного расширена и, возможно, немного более читабельна

var createClickHandler = function(arg) {
  return function() { alert(arg); };
}

for(var a=0;a<10;a++) {
    var b=document.createElement('b')
    b.onclick = createClickHandler(a);
    b.innerHTML=a
    document.body.appendChild(b)
}

Один грязный обходной путь, который я обнаружил, заключается в использовании .value свойство созданного объекта для хранения аргумента, который мы хотим передать .onclick функция. Так что я могу сделать что-то вроде

for(var a=0;a<10;a++) {
    var b=document.createElement('b')
    b.value=a
    b.onclick=function() {
        myfunc(this.value)
    }
    b.innerHTML=a
    document.body.appendChild(b)
}
function myfunc(n){
  console.log(n)
}

Я не уверен, работает ли.value с каждым элементом, но, например, для DIV.

РЕДАКТИРОВАТЬ: Чтобы передать больше значений, чем одно, вы можете объединить их, используя некоторый символ, например _, а затем разделить его

b.value=x+"_"+y+"_"+z

function myfunc(str){
 t=str.split("_")
 x=t[0]
 y=t[1]
 z=t[2]
 console.log(x+","+y+","+z)
}
Другие вопросы по тегам