Javascript中嵌套函数的变量范围

emk*_*kay 2 javascript variables scope nested function

我查看了无数的例子,表明这应该有用,但事实并非如此.我想知道是否有人可以看一看并说明原因.我试图从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);
}
Run Code Online (Sandbox Code Playgroud)

T.J*_*der 11

有两个问题:

第一个是你传递到函数setTimeout有一个持久的引用dia变量,不是一个副本dia的价值作为创建功能时的感觉.因此,当功能运行时,他们都看到了相同的值dia,这是它的价值,然后,在循环完成后.

这个例子可能有助于使这更清楚:

var a = 1;
setTimeout(function() {
    alert(a);
}, 0);
a = 2;
setTimeout(function() {
    alert(a);
}, 0);
Run Code Online (Sandbox Code Playgroud)

上面的代码两次显示"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();
    };
}
Run Code Online (Sandbox Code Playgroud)

因为函数buildFunction返回结束d,它不会改变,而不是改变dia,它会给我们创建时的值.

第二个问题是你的循环条件不正确,这就是你看到的原因undefined.你的循环是:

for(dcount = 0; dcount <= dialogue.length; dcount++)   {
Run Code Online (Sandbox Code Playgroud)

没有任何元素dialogue[dialogue.length].最后一个元素是dialogue[dialogue.length - 1].你应该退出你的循环< dialogue.length,而不是<= dialogue.length.有了< dialogue.length,你仍然有一个问题:dia永远是最后一个条目(见上文),但至少它不会是未定义的.