Замыкания JavaScript и область видимости переменных

У меня проблемы с закрытием JS:

// arg: an array of strings. each string is a mentioned user.
// fills in the list of mentioned users. Click on a mentioned user's name causes the page to load that user's info.
function fillInMentioned(mentions) {
    var mentionList = document.getElementById("mention-list");
    mentionList.innerHTML = "";
    for (var i = 0; i < mentions.length; i++) {
        var newAnchor = document.createElement("a");

        // cause the page to load info for this screen name
        newAnchor.onclick = function () { loadUsernameInfo(mentions[i]) };

        // give this anchor the necessary content
        newAnchor.innerHTML = mentions[i];

        var newListItem = document.createElement("li");
        newListItem.appendChild(newAnchor);
        mentionList.appendChild(newListItem);
    }
    document.getElementById("mentions").setAttribute("class", ""); // unhide. hacky hack hack.
}

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

loadUserNameInfo(undefined);

Почему это? Моя цель - такой якорь:

<a onclick="loadUserNameInfo(someguy)">someguy</a>

Как я могу это произвести?

Обновить. Это работает:

newAnchor.onclick = function () { loadUsernameInfo(this.innerHTML) };
newAnchor.innerHTML = mentions[i];

person Nick Heiner    schedule 22.02.2010    source источник
comment
Это один из наиболее распространенных и повторяющихся вопросов относительно закрытий и возможных дубликатов: stackoverflow.com/questions/1734749 stackoverflow.com/questions/643542 stackoverflow.com/ questions / 1582634 stackoverflow.com/questions/1331769 stackoverflow.com/questions/1552941 stackoverflow.com/questions/750486 stackoverflow.com/questions/933343 stackoverflow.com/ questions / 1579978 stackoverflow.com/questions/1413916   -  person Christian C. Salvadó    schedule 23.02.2010


Ответы (2)


Ссылка «i» внутри замыкания для обработчиков onclick перехватывает текущую ссылку на «i». Он обновляется для каждого цикла, что также влияет на все созданные замыкания. Когда ваш цикл while заканчивается, «i» находится сразу за концом массива упоминаний, поэтому упоминания [i] == undefined для всех из них.

Сделай это:

newAnchor.onclick = (function(idx) {
    return function () { loadUsernameInfo(mentions[idx]) };
})(i);

чтобы заставить «i» зафиксироваться в значении idx внутри замыкания.

person Ben Zotto    schedule 22.02.2010
comment
это не работает. Mentions - это не глобальная переменная, поэтому она не будет доступна из функции onclick, верно? - person Nick Heiner; 23.02.2010
comment
Как заметил Бен, мой ответ был ошибочным. Я собирался перефразировать это именно так. +1 и извините если кого перепутала - person Pablo Fernandez; 23.02.2010
comment
@Rosarch каждая переменная / функция «более высокой» области видимости может быть видна в «более низкой» области. - person Pablo Fernandez; 23.02.2010

Ваш итератор i хранится как ссылка, а не как значение, и поэтому, поскольку он изменяется вне замыкания, все ссылки на него изменяются.

попробуй это

function fillInMentioned(mentions) { 
    var mentionList = document.getElementById("mention-list"); 
    mentionList.innerHTML = ""; 
    for (var i = 0; i < mentions.length; i++) { 
        var newAnchor = document.createElement("a"); 

        // Set the index as a property of the object 
        newAnchor.idx = i;
        newAnchor.onclick = function () { 
            // Now use the property of the current object
            loadUsernameInfo(mentions[this.idx]) 
        }; 

        // give this anchor the necessary content 
        newAnchor.innerHTML = mentions[i]; 

        var newListItem = document.createElement("li"); 
        newListItem.appendChild(newAnchor); 
        mentionList.appendChild(newListItem); 
    } 
    document.getElementById("mentions").setAttribute("class", "");  
} 
person Greg B    schedule 22.02.2010