[英]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.