关于dom:JavaScript闭包和变量范围

JavaScript closures and variable scope

我在JS闭包时遇到问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 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.
}

不幸的是,单击其中一个锚标签会导致这样的调用:

1
loadUserNameInfo(undefined);

为什么是这样? 我的目标是像这样的锚:

1
someguy

我该如何制作?

更新此作品:

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


闭包内的onclick处理程序的"i"引用正在捕获"i"的实时引用。 它会针对每个循环进行更新,这会影响到目前为止创建的所有闭包。 当你的while循环结束时,"i"刚好超过了mentions数组的结尾,所以提到[i] == undefined为所有这些。

做这个:

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

强制"i"锁定闭包内的值idx。


您的迭代器i存储为引用,而不是作为值存储,因此,当它在闭包外部更改时,对它的所有引用都在变化。

试试这个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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","");  
}