Установка 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 при установке onclick?

Ответы

Ответ 1

Попробуйте выполнить

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

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

Решение работает вокруг этого, создавая новую функцию и значение для каждой области, а затем сразу же устанавливая это значение на текущее значение 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)
}

Ответ 2

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

EDIT: чтобы передать больше значений, то вы можете объединить их с помощью какого-либо символа, как _, а затем разделить его

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