【问题标题】:JavaScript closures and variable scopeJavaScript 闭包和变量作用域
【发布时间】:2011-01-19 19:51:40
【问题描述】:

我遇到了 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];

【问题讨论】:

标签: javascript dom events closures


【解决方案1】:

onclick 处理程序的闭包内的“i”引用正在捕获对“i”的实时引用。它会针对每个循环进行更新,这也会影响迄今为止创建的所有闭包。当您的 while 循环结束时,“i”刚刚超过了提及数组的末尾,因此所有这些都提到了 [i] == undefined。

这样做:

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

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

【讨论】:

  • 那行不通。 Mentions 不是全局变量,因此无法通过 onclick 函数访问它,对吧?
  • 正如 Ben 指出的,我的回答有缺陷。我打算完全像这样改写它。 +1,如果我让任何人感到困惑,我们深表歉意
  • @Rosarch “更高”范围的每个变量/函数都可以在“更低”范围中看到。
【解决方案2】:

您的迭代器 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", "");  
} 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-18
    • 2010-10-12
    • 2013-09-08
    • 1970-01-01
    • 2014-02-13
    • 2013-01-01
    • 2018-09-09
    • 2011-05-02
    相关资源
    最近更新 更多