JavaScript-замыкания и переменная область видимости - PullRequest
3 голосов
/ 23 февраля 2010

У меня проблемы с закрытием 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];

Ответы [ 2 ]

7 голосов
/ 23 февраля 2010

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

Сделайте это:

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

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

2 голосов
/ 23 февраля 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", "");  
} 
...