簡體   English   中英

Javascript中嵌套函數的變量范圍

[英]Variable scope in nested functions in Javascript

我查看了無數的例子,表明這應該有用,但事實並非如此。 我想知道是否有人可以看一看並說明原因。 我試圖從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);
}

有兩個問題:

第一個是你傳遞給setTimeout的函數有一個對dia變量的持久引用而不是創建函數時dia的值的副本 因此,當功能運行時,他們都看到相同的值dia ,這是它有那么值,循環完成后。

這個例子可能有助於使這更清楚:

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

上面的代碼兩次顯示“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();
    };
}

因為函數buildFunction返回關閉d ,它不會改變,而不是dia ,它確實給出了它在創建時的值。

第二個問題是你的循環條件不正確,這就是你看到undefined 你的循環是:

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

dialogue[dialogue.length]沒有元素dialogue[dialogue.length] 最后一個元素是dialogue[dialogue.length - 1] 您應該使用< dialogue.length ,而不是<= dialogue.length dialog.length退出循環。 使用< dialogue.length ,你仍然有一個問題: 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(count) {
    alert(dialogue[count]);

}, loopDelay,dcount);
}

這個解決方案只是將參數傳遞給setTimeout函數,因此它可以從那里獲取數組索引並獲取正確的項

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM