Javascript - использовать значение переменной (напрямую, а не по ссылке) при объявлении асинхронной функции - PullRequest
0 голосов
/ 11 октября 2011

Хорошо,

У меня есть что-то похожее на это:

for (j = 0; j < btnArr.length; j++)
{
    var btn = document.createElement("button");
    btn.addEventListener("click", function() { press(this, j) }, false);
    div.appendChild(btn);
}

Моя проблема в том, что, поскольку событие происходит в последнее время, j уже изменило значениепо времени срабатывает функция события.Я хочу, чтобы функция напрямую использовала значение j при объявлении функции, а не ссылку на сам j.

Если бы вторым параметром addEventListener была строка, она выглядела бы каккак это:

btn.addEventListener("click", "function() { press(this, " + j + ") }", false);

Кто-нибудь знает, возможно ли это и как это сделать?

Я попытался немного поискать, но не могу найти ничего подходящего, так как проблематрудно описать правильно только несколькими словами.

Кстати, это для скрипта Greasemonkey, поэтому используется .addEventListener() вместо .onclick = (...)

Ответы [ 4 ]

2 голосов
/ 11 октября 2011

Вам просто нужно разорвать контекст. Это можно сделать множеством способов, но Function.bind является наиболее элегантным ИМХО. Поскольку вы находитесь в Firefox, привязка должна быть там.

for (j = 0; j < btnArr.length; j++)
{
    var btn = document.createElement("button");
    btn.addEventListener("click", function(value) { press(this, value) }.bind(btn, j), false);
    div.appendChild(btn);
}

Для альтернативного подхода напишите функцию, которая возвращает обработчик.

for (j = 0; j < btnArr.length; j++)
{
    var btn = document.createElement("button");
    btn.addEventListener("click", getHandler(j), false);
    div.appendChild(btn);
}

function getHandler(j) {
    return function() { press(this, j) };
}

Еще один вариант - добавить свойство к элементу button.

for (j = 0; j < btnArr.length; j++)
{
    var btn = document.createElement("button");
    btn.myValue = j;
    btn.addEventListener("click", function() { press(this, this.myValue); }, false);
    div.appendChild(btn);
}
1 голос
/ 11 октября 2011

btn - это объект, и вы всегда можете добавить свои собственные свойства и получить к ним доступ позже:

for (var j = 0; j < btnArr.length; j++)
{
    var btn = document.createElement("button");
    btn.index = j;
    btn.addEventListener("click", function() { press(this, this.index) }, false);
    div.appendChild(btn);
}

См. http://jsfiddle.net/Kai/Y2KaZ/

1 голос
/ 11 октября 2011

Вы столкнулись с вековой проблемой замыканий в слушателях. Вы можете использовать:

btn.addEventListener("click", (function(x) {
                                 return function(){
                                    press(this, x) 
                                 };
                               }(j)), false);

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

btn = null;

чтобы сломать замыкание. Есть много ответов на это на SO. Вы можете использовать bind , но это доступно не во всех браузерах.

0 голосов
/ 11 октября 2011

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

function make_handler(i){
    //you can use j here as well instead of i
    //I'm just avoiding shadowing for didactic reasons...
    return function() { press(this, i) };
}

for (j = 0; j < btnArr.length; j++)
{
    var btn = document.createElement("button");
    btn.addEventListener("click", make_handler(j), false);
    div.appendChild(btn);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...