2

我查看了无数示例,这些示例表明这应该有效,但事实并非如此。我想知道是否有人可以看看并指出原因。我试图从 setTimeout 函数中访问变量“dia”,但它总是返回未定义的:

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);
}
4

2 回答 2

11

有两个问题:

首先是您传入的函数setTimeout具有对变量的持久引用,而不是创建函数时的' 值的副本。因此,当函数运行时,它们都会看到相同的值 for ,也就是在循环完成后它具有then的值。diadiadia

这个例子可能有助于更清楚地说明这一点:

var a = 1;
setTimeout(function() {
    alert(a);
}, 0);
a = 2;
setTimeout(function() {
    alert(a);
}, 0);

上面的代码向我们显示了两次“2”。它没有向我们显示“1”,然后是“2”。这两个函数在运行a时都按原样访问。

如果您考虑一下,这正是全局变量的工作方式。事实上,这是有原因的:这正是全局变量的工作方式。:-)

更多:闭包并不复杂

现在,有时,您想要获取dia函数创建时的 ' 值的副本。在这些情况下,您通常使用构建器函数并将dia其作为参数传递给它。builder 函数创建一个关闭参数的函数,而不是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返回 closes over d,它不会改变,而不是dia,它会改变,它给了我们创建它时的值。

第二个问题是您的循环条件不正确,这就是您看到undefined. 你的循环是:

for(dcount = 0; dcount <= dialogue.length; dcount++)   {

处没有元素dialogue[dialogue.length]。最后一个元素在dialogue[dialogue.length - 1]。你应该退出你的循环< dialogue.length,而不是<= dialogue.length。使用< dialogue.length,您仍然会遇到问题:dia始终是最后一个条目(见上文),但至少它不会是未定义的。

于 2013-08-05T21:11:08.913 回答
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 函数,以便它可以从那里获取数组索引并获取正确的项目

于 2013-08-05T21:16:36.200 回答