2012-03-02 43 views
6

我会很快,并直接跳到案件。代码被评论,所以你知道我的意图。基本上,我正在构建一个基于HTML5的小型游戏,并且反对在服务器或cookie中保存内容,我只是给玩家提供一个关卡代码。当玩家将代码(以简单散列形式)输入到文本输入字段中,并单击按钮加载该级别时,将调用函数“l”。该函数首先检索玩家的条目,然后迭代散列列表并对其进行比较。当一场比赛很喜欢,那个水平应该被加载,但是有错误。我做了一些调试,发现iterator(“i”)的值在setTimeout内部发生了变化!我想暂停1秒,因为立即加载关卡会太快而且看起来很糟糕。setTimeout似乎正在改变我的变量!为什么?

levelCodes = //Just a set of "hashes" that the player can enter to load a certain level. For now, only "code" matters. 
[ 
    {"code": "#tc454", "l": 0}, 
    {"code": "#tc723", "l": 1}, 
] 

var l = function() //This function is called when a button is pressed on the page 
{ 
    var toLoad = document.getElementById("lc").value; //This can be "#tc723", for example 

    for (i = 0; i < levelCodes.length; i++) //levelCodes.length == 2, so this should run 2 times, and in the last time i should be 1 
     if (levelCodes[i].code == toLoad) //If I put "#tc723" this will be true when i == 1, and this happens 
     { 
      console.log(i); //This says 1 
      setTimeout(function(){console.log(i)}, 1000); //This one says 2! 
     } 
} 
+1

不错的评论,有所有upvotes。 – ninjagecko 2012-03-02 21:13:21

+0

仅供参考,您的代码不会通过jslint的几个原因,并会在一些浏览器中产生错误 – 2012-03-02 21:32:31

+0

@MarkSchultheiss,请解释一下,我认为jsLint是某种评估者,是对的吗?那么,你能告诉我为什么不计算? – corazza 2012-03-02 21:47:41

回答

3

for循环不断递增i直到循环条件满足,即使在for循环的代码不执行,当setTimeout代码执行它显示的i当前值 - 这是2

4

ECMAscript使用lexical closures的技术,这是对所有父上下文对象/词汇环境记录(ES3/ES5)的内部存储。

简而言之,您使用的匿名函数setTimeout关闭了该变量,因此当该超时值“等待”时,循环会继续。 setTimeout operatores asynronously当然那又意味着,在时间循环已完成值,如果i当然是2

现在还记得关于封闭的东西,我们在setTimeout匿名函数仍持有到i时参考它终于发生(1000毫秒后)。所以它正确地显示了你的值2.

如果你想在1000ms后显示每次迭代的数字,你需要调用另一个上下文。这可能看起来类似于

setTimeout((function(local) { 
    return function() { 
     console.log(local); 
    }; 
}(i)), 1000); 
+0

+1例如清除本地 – 2012-03-02 21:29:39

5

其他人已经写出了你所得到的行为的原因。现在的解决方案:改变setTimeout行:

(function(i) { 
    setTimeout(function(){console.log(i)}, 1000); 
})(i); 

这工作,因为它抓住了可变i的当前值到另一封,而封内的变量不发生改变。

+0

+1,但要说清楚:(function(iwas){ setTimeout(function(){console.log(iwas)},1000);})(i); - 通过'我'在 – 2012-03-02 21:26:54

1

的时候setTimeout的回调得到执行可变将有2的值,因为你不退出循环,保持计数,直到它等于levelCodes.legnth(也就是2)。 基本上你需要在调用setTimeout后加返回中断。 此外,你没有声明变量,所以它将被绑定到全局命名空间,这是不好的,可能会导致非常晦涩的错误。例如,可以在其他函数中更改值i,因此setTimeout回调将会看到不同的值。您需要添加var i;函数开头l

+0

我看到这暗示全球变量我也 – 2012-03-02 21:30:21

相关问题