我查看了无数的例子,表明这应该有用,但事实并非如此。我想知道是否有人可以看一看并说明原因。我试图从setTimeout函数中访问变量“dia”,但它总是返回undefined:
var dialogue = new Array();
dialogue[0] = 'Hi there Mo, I am Mark. I will be guiding through the game for you today';
dialogue[1] = 'Hey there Mark, how you doing?';
dialogue[2] = 'I am doing fine sweetie pie, how about yourself?';
dialogue[3] = 'I am good too, thanks. Are you ready for today, i.e. the big day?';
dialogue[4] = 'I certainly am, Mark';
var dcount;
var loopDelay;
var diatext;
for(dcount = 0; dcount <= dialogue.length; dcount++) {
var dia = dialogue[dcount];
if(dcount == 0) { loopDelay = 0; } else {
loopDelay = ((dia.length)*1000)/18;
}
setTimeout(function() {
alert(dia);
diatext = Crafty.e('2D, DOM, Text')
.text(dia)
.textFont({ size: '11px', weight: 'bold' })
.attr({ x: 200, y: 150, w:400, h:300})
.css();
}, loopDelay);
}
答案 0 :(得分:11)
有两个问题:
首先,您传入setTimeout
的函数对dia
变量持久参考,不 a 在创建函数时复制dia
的值。因此,当函数运行时,它们都会看到dia
的相同值,即在循环完成后它具有然后的值。
这个例子可能有助于使这一点更加清晰:
var a = 1;
setTimeout(function() {
alert(a);
}, 0);
a = 2;
setTimeout(function() {
alert(a);
}, 0);
上面的代码两次显示“2”。它不会向我们显示“1”然后显示“2”。这两个函数在运行时访问a
。
如果你考虑一下,这正是全局变量的工作原理。事实上,这是有原因的:它正是全局变量的工作方式。 : - )
更多:Closures are not complicated
现在,有时候,您希望在创建函数时获得dia
值的副本。在这些情况下,您通常使用构建器函数并将dia
作为参数传递给它。构建器函数创建一个关闭参数的函数,而不是dia
:
for(dcount = 0; dcount <= dialogue.length; dcount++) { // But see note below about <=
var dia = dialogue[dcount];
if(dcount == 0) { loopDelay = 0; } else {
loopDelay = ((dia.length)*1000)/18;
}
setTimeout(buildFunction(dia), loopDelay);
}
function buildFunction(d) {
return function(d) {
alert(d);
diatext = Crafty.e('2D, DOM, Text')
.text(d)
.textFont({ size: '11px', weight: 'bold' })
.attr({ x: 200, y: 150, w:400, h:300})
.css();
};
}
因为函数buildFunction
返回d
而不是dia
,而不是undefined
,它会为我们提供创建时的值。< / p>
第二个问题是您的循环条件不正确,这就是您看到for(dcount = 0; dcount <= dialogue.length; dcount++) {
的原因。你的循环是:
dialogue[dialogue.length]
dialogue[dialogue.length - 1]
没有元素。最后一个元素位于< dialogue.length
。您应该使用<= dialogue.length
退出循环,而不是< dialogue.length
。使用dia
,您仍然会遇到问题:{{1}}始终是最后一个条目(见上文),但至少它不会是未定义的。
答案 1 :(得分:1)
试试这个
var dialogue = new Array();
dialogue[0] = 'Hi there Mo, I am Mark. I will be guiding through the game for you today';
dialogue[1] = 'Hey there Mark, how you doing?';
dialogue[2] = 'I am doing fine sweetie pie, how about yourself?';
dialogue[3] = 'I am good too, thanks. Are you ready for today, i.e. the big day?';
dialogue[4] = 'I certainly am, Mark';
var dcount;
var loopDelay;
var diatext;
for(dcount = 0; dcount < dialogue.length; dcount++) {
var dia = dialogue[dcount];
if(dcount == 0) { loopDelay = 0; } else {
loopDelay = ((dia.length)*1000)/18;
}
setTimeout(function(count) {
alert(dialogue[count]);
}, loopDelay,dcount);
}
这个解决方案只是将一个参数传递给setTimeout函数,这样就可以从那里获取数组索引并获取正确的项