2

これが機能するはずであることを示す無数の例を見てきましたが、そうではありません。誰かが見て、その理由を示すことができるかどうか疑問に思っていました. 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);
}
4

2 に答える 2

11

2 つの問題があります。

1 つ目は、関数が作成された時点での の値のコピーではなく、渡す関数が変数への永続的な参照setTimeoutを持っていることです。そのため、関数が実行されると、ループが完了した後、すべての関数が に対して同じ値を参照します。これは、そのときの値です。diadiadia

次の例は、これをより明確にするのに役立ちます。

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

上記のコードでは、「2」が 2 回表示されます。「1」と「2」は表示されません。どちらの機能も、実行a時にそのままアクセスします。

考えてみれば、これはまさにグローバル変数がどのように機能するかです。実際、それには理由があります。それは、まさにグローバル変数が機能する方法です。:-)

詳細:閉鎖は複雑ではありません

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

この関数は、変更される ではなく、変更されないbuildFunctioncloses over を返すため、作成時の値が得られます。ddia

2 番目の問題は、ループ条件が正しくないことです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 に答える