Javascript 嵌套函数中的变量范围
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18067742/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Variable scope in nested functions in Javascript
提问by emkay
I have looked through countless examples which indicate that this is supposed to work, but it does not. I was wondering if someone could have a look and indicate why. I am trying to access the variable "dia" from within the setTimeout function, but it always returns undefined:
我查看了无数示例,这些示例表明这应该有效,但事实并非如此。我想知道是否有人可以看看并指出原因。我试图从 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);
}
回答by T.J. Crowder
There are two problems:
有两个问题:
The first is that the function you're passing into setTimeout
has an enduring referenceto the dia
variable, nota copyof dia
's value as of when the function was created. So when the functions run, they all see the same value for dia
, which is the value it has then, after the loop is complete.
第一个是你传递到函数setTimeout
有一个持久的引用的dia
变量,不是一个副本的dia
的价值作为创建功能时的感觉。因此,当函数运行时,它们都会看到相同的 值dia
,即循环完成后它具有then的值。
This example may help make this clearer:
这个例子可能有助于更清楚地说明这一点:
var a = 1;
setTimeout(function() {
alert(a);
}, 0);
a = 2;
setTimeout(function() {
alert(a);
}, 0);
The code above shows us "2" twice. It does not show us "1" and then "2". Both functions access a
as it is when they run.
上面的代码向我们显示了两次“2”。它不会向我们显示“1”然后是“2”。这两个函数a
在运行时都按原样访问。
If you think about it, this is exactly how global variables work. And in fact, there's a reason for that: It's exactly the way global variables work. :-)
如果你仔细想想,这正是全局变量的工作方式。事实上,这是有原因的:这正是全局变量的工作方式。:-)
More: Closures are not complicated
更多:闭包并不复杂
Now, sometimes, you want to get a copy of dia
's value as of when the function was created. In those cases, you usually use a builder function and pass dia
to it as an argument. The builder function creates a function that closes over the argument, rather than dia
:
现在,有时,您想要获取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();
};
}
Because the function buildFunction
returns closes over d
, which doesn't change, rather than dia
, which does, it gives us the value as of when it was created.
因为函数buildFunction
返回 closes over d
,它不会改变,而不是dia
,它会改变,它为我们提供了它创建时的值。
The second problem is that your loop condition is incorrect, which is why you're seeing undefined
. Your loop is:
第二个问题是您的循环条件不正确,这就是为什么您看到undefined
. 你的循环是:
for(dcount = 0; dcount <= dialogue.length; dcount++) {
There is no element at dialogue[dialogue.length]
. The last element is at dialogue[dialogue.length - 1]
. You should be exiting your loop with < dialogue.length
, not <= dialogue.length
. With < dialogue.length
, you'd still have a problem: dia
would always be the last entry (see above), but at least it wouldn't be undefined.
在 处没有元素dialogue[dialogue.length]
。最后一个元素在dialogue[dialogue.length - 1]
。您应该使用< dialogue.length
,而不是退出循环<= dialogue.length
。使用< dialogue.length
,您仍然会遇到问题:dia
将始终是最后一个条目(见上文),但至少它不会是未定义的。
回答by user1549458
try this
试试这个
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);
}
This solution just pass an argument to the setTimeout function so it can take the array index from there and take the correct item
这个解决方案只是将一个参数传递给 setTimeout 函数,这样它就可以从那里获取数组索引并获取正确的项目