简体   繁体   English

Javascript中嵌套函数的变量范围

[英]Variable scope in nested functions in Javascript

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”,但它总是返回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);
}

There are two problems: 有两个问题:

The first is that the function you're passing into setTimeout has an enduring reference to the dia variable, not a copy of dia 's value as of when the function was created. 第一个是你传递给setTimeout的函数有一个对dia变量的持久引用而不是创建函数时dia的值的副本 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. 因此,当功能运行时,他们都看到相同的值dia ,这是它有那么值,循环完成后。

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. 上面的代码两次显示“2”。 It does not show us "1" and then "2". 它不会向我们显示“1”然后显示“2”。 Both functions access a as it is when they run . 这两个函数访问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. 现在,有时候,你想要在创建函数时获得dia的值的副本。 In those cases, you usually use a builder function and pass dia to it as an argument. 在这些情况下,您通常使用构建器函数并将dia作为参数传递给它。 The builder function creates a function that closes over the argument , rather than 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();
    };
}

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返回关闭d ,它不会改变,而不是dia ,它确实给出了它在创建时的值。

The second problem is that your loop condition is incorrect, which is why you're seeing undefined . 第二个问题是你的循环条件不正确,这就是你看到undefined Your loop is: 你的循环是:

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

There is no element at dialogue[dialogue.length] . dialogue[dialogue.length]没有元素dialogue[dialogue.length] The last element is at dialogue[dialogue.length - 1] . 最后一个元素是dialogue[dialogue.length - 1] You should be exiting your loop with < dialogue.length , not <= dialogue.length . 您应该使用< dialogue.length ,而不是<= dialogue.length dialog.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.length ,你仍然有一个问题: dia总是最后一个条目(见上文),但至少它不会是未定义的。

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函数,因此它可以从那里获取数组索引并获取正确的项

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM