1

可能重复:
Javascript臭名昭著的循环问题?

我有一个小问题,如果你们中的一些人能意识到这里缺少什么样的逻辑,那就太好了,因为我似乎找不到它:

我有一个包含先前操作结果的数组。假设数组是:

var results = [0, 1];

然后我有一堆代码,我在其中创建了一些按钮,并在for循环中为这些按钮分配了不同的功能,具体取决于数组的位置。问题是由于某种原因,所有创建的按钮(在这种情况下是两个)都带有分配给数组最后一个值的函数(在这种情况下,两者都会作为一个出现,而不是第一个带有 0 和第二个有 1)

这是代码:

for (var i = 0; i < results.length; i++) {
    var br2 = b.document.createElement("br");
    var reslabel = b.document.createTextNode(Nom[results[i]].toString());
    var card = document.createElement("input");
    card.type = "button";
    id = results[i]; // this is the problematic value. 
    card.onclick = newcard; // this function will use the above value.
    card.value = "Show card";
    divcontainer.appendChild(br2);
    divcontainer.appendChild(reslabel);
    divcontainer.appendChild(card);
} 

实际上,此代码生成的按钮与数组中的元素一样多,每个按钮都有其正确的标签(它从另一个数组中检索标签)。一切都很好。然后,我点击按钮。所有按钮都应该运行该newcard功能。该函数需要id变量,所以在这种情况下它应该是:

  • 第一个按钮:使用值为 0 的newcard变量运行id
  • 第二个按钮:使用值为 1 的newcard变量运行id

但是两个按钮都使用id1 来运行……这是为什么呢?

这可能很简单,或者只是在我的时区已经很晚了:-)无论如何,我会很感激任何评论。我在这里学到了很多...

谢谢!

编辑以添加 newcard 的定义:

function newcard() {
    id = id;
    var toerase = window.document.getElementById("oldcard");
    toerase.innerHTML = "";
    generate();
}

该函数generate将使用id. 没有错,它生成的内容很好,只是id总是设置为数组中的最后一项。

4

2 回答 2

3

在继续之前,非常感谢bfavaretto解释了一些完全让我无法理解的范围界定细节。似乎除了您遇到的问题之外,您还遭受了范围界定的困扰,当我试图制定答案时,这让我很苦恼。

无论如何,这是一个有效的例子。我正在使用 forEach,某些浏览器可能不支持它。然而,它确实解决了一些让你感到悲伤的范围界定问题:

<html>
<body>
<script>
var results = [0,1];
results.forEach( function(result) {
    var card = document.createElement("input");
    card.type = "button";
    card.onclick = function() {
        newcard( result );
    } 
    card.value = "Show card";
    document.body.appendChild(card);
}); 

function newcard(x) {
   alert(x);
}
</script>
</body>
</html>

如果您决定坚持使用传统循环,请参阅 bfavaretto 的回答。

于 2012-12-22T00:41:28.233 回答
3

id是一个全局变量,当循环结束时,它被设置为数组的最后一个值。当事件处理程序代码运行并请求 的值时id,它将获得最后一个值。

您需要创建一个闭包来捕获电流results[i]并将其传递(这是一个非常常见的陷阱,请参阅Javascript infamous Loop problem?)。由于newcard很简单,而且id实际用在 中generate,所以可以修改generate为以 id 作为参数。然后你就不再需要newcard了,你可以这样做:

card.onclick = (function(id) { 
    return function() { 
        window.document.getElementById("oldcard").innerHTML = "";
        generate(id);
    }; 
}(results[i]));

它的作用是定义并立即调用传递给 current 的函数results[i]。它返回另一个函数,这将是您的实际onclick处理程序。该函数可以访问id外部函数的参数(称为闭包)。在循环的每次迭代中,将创建一个新的闭包,将每个单独的闭包捕获id以供自己使用。

于 2012-12-22T01:08:49.080 回答