循环中的javascript闭包

循环中的javascript闭包,javascript,Javascript,sombody能解释为什么会这样吗?或者是这种模式的另一种选择?我的情况是这样的:我收到一个包含消息的数组,我必须按顺序处理它们,一个同步地处理另一个。问题是一些消息需要触发一系列动画(jqwuery animate(),它是异步的),并且在最后一个动画完成之前无法处理以下消息。由于javascript中没有sleep(),所以我尝试使用这样的模式,即消息在完成后调用下一个(对于动画,我只需将“next”函数指针传递给animate的“complete”回调)。无论如何,我想动态地构建这个“链”

sombody能解释为什么会这样吗?或者是这种模式的另一种选择?我的情况是这样的:我收到一个包含消息的数组,我必须按顺序处理它们,一个同步地处理另一个。问题是一些消息需要触发一系列动画(jqwuery animate(),它是异步的),并且在最后一个动画完成之前无法处理以下消息。由于javascript中没有sleep(),所以我尝试使用这样的模式,即消息在完成后调用下一个(对于动画,我只需将“next”函数指针传递给animate的“complete”回调)。无论如何,我想动态地构建这个“链”,但发现了这种奇怪的(?)行为

思考您在闭包中捕获的值

//I have the following function:
    function handle_message(msg)
    {
        //do work
        console.log('some work: '+msg.val);
        //call next message
        msg.next();
    }

//And array of message objects:
var msgs = [ {val : 'first msg'}, { val : 'second msg'}, { val : 'third msg'}];

//I link messages by setting next parameter in a way that it calls handle_message for the next msg in the list. Last one displays alert message.
msgs[2].next = function() {alert('done!')};
msgs[1].next = function() {handle_message(msgs[2]);};
msgs[0].next = function() {handle_message(msgs[1]);};

//Start the message handle "chain". It works!
handle_message(msgs[0]);

//======== Now I do exactly the same thing but I link messages using the for loop:

for (var i=msgs.length-1; i>=0; i--)
{
    if (i==msgs.length-1)
    {
        msgs[i].next = function() {alert('done!');};
    }
    else
    {
        msgs[i].next = function() {handle_message(msgs[i+1]);};
    }
}

//Start the message handling chain. It fails! It goes into infinite recursion (second message calls itself)
handle_message(msgs[0]);
这将捕获
i
的值,但它会更改下一次迭代,从而获得一个无限循环


在循环结束时,i是
-1
,因此
i+1
将一次又一次地成为同一条消息。

想想你在闭包中捕获的值

//I have the following function:
    function handle_message(msg)
    {
        //do work
        console.log('some work: '+msg.val);
        //call next message
        msg.next();
    }

//And array of message objects:
var msgs = [ {val : 'first msg'}, { val : 'second msg'}, { val : 'third msg'}];

//I link messages by setting next parameter in a way that it calls handle_message for the next msg in the list. Last one displays alert message.
msgs[2].next = function() {alert('done!')};
msgs[1].next = function() {handle_message(msgs[2]);};
msgs[0].next = function() {handle_message(msgs[1]);};

//Start the message handle "chain". It works!
handle_message(msgs[0]);

//======== Now I do exactly the same thing but I link messages using the for loop:

for (var i=msgs.length-1; i>=0; i--)
{
    if (i==msgs.length-1)
    {
        msgs[i].next = function() {alert('done!');};
    }
    else
    {
        msgs[i].next = function() {handle_message(msgs[i+1]);};
    }
}

//Start the message handling chain. It fails! It goes into infinite recursion (second message calls itself)
handle_message(msgs[0]);
这将捕获
i
的值,但它会更改下一次迭代,从而获得一个无限循环


循环结束时,我是
-1
,因此
i+1
将是一个又一个相同的消息。

我认为问题在于
i
没有您认为它具有的值:

msgs[i].next = function() {handle_message(msgs[i+1]);};

参见循环中的第5点闭包at

我认为问题在于
I
没有您认为它具有的值:

msgs[i].next = function() {handle_message(msgs[i+1]);};

参见点#5循环中的闭包

您需要一个闭包才能使其工作:

// i is defined here:
for (var i=msgs.length-1; i>=0; i--)
{
    if (i==msgs.length-1)
    {
        msgs[i].next = function() {alert('done!');};
    }
    else
    {
        msgs[i].next = function() {
            // when this line gets executed, the outer loop is long finished
            // thus i equals -1
            handle_message(msgs[i+1]);
        };
    }
}
现场演示:

说明:

此函数表达式存在问题:

function handle_message( msg ) {
    console.log( 'some work: ' + msg.val );
    msg.next();
}

var msgs = [{val :'first msg'},{val:'second msg'},{val:'third msg'}];

for ( var i = msgs.length - 1; i >= 0; i-- ) {
    (function(i) {
        if ( i == msgs.length - 1 ) {
            msgs[i].next = function() { alert( 'done!' ); };
        } else {
            msgs[i].next = function() { handle_message( msgs[i + 1] ); };
        }
    })(i);
}

handle_message( msgs[0] );

此函数具有对
i
变量的实时引用。调用此函数时,for的
循环已结束,且
i
的值为
-1
。如果要捕获
i
的当前值(迭代过程中的值),则需要额外的包装函数。此函数永久捕获
i
的当前值(作为参数)。

您需要一个闭包才能使其工作:

// i is defined here:
for (var i=msgs.length-1; i>=0; i--)
{
    if (i==msgs.length-1)
    {
        msgs[i].next = function() {alert('done!');};
    }
    else
    {
        msgs[i].next = function() {
            // when this line gets executed, the outer loop is long finished
            // thus i equals -1
            handle_message(msgs[i+1]);
        };
    }
}
现场演示:

说明:

此函数表达式存在问题:

function handle_message( msg ) {
    console.log( 'some work: ' + msg.val );
    msg.next();
}

var msgs = [{val :'first msg'},{val:'second msg'},{val:'third msg'}];

for ( var i = msgs.length - 1; i >= 0; i-- ) {
    (function(i) {
        if ( i == msgs.length - 1 ) {
            msgs[i].next = function() { alert( 'done!' ); };
        } else {
            msgs[i].next = function() { handle_message( msgs[i + 1] ); };
        }
    })(i);
}

handle_message( msgs[0] );

此函数具有对
i
变量的实时引用。调用此函数时,for
循环已结束,且
i
的值为
-1
。如果要捕获
i
的当前值(迭代过程中的值),则需要额外的包装函数。此函数永久捕获
i
的当前值(作为参数)。

您真的应该为此使用类,对象和原型。这是一个非常糟糕的问题标题。在未来,请尝试总结您看到的困惑您的结果,或您试图实现的结果。你也可以发布一个题为“我很困惑”或“帮助”的问题。你是对的,我已经更改了它。你的可能副本应该真的使用类,对象和原型。这是一个非常糟糕的问题标题。在未来,请尝试总结您看到的困惑您的结果,或您试图实现的结果。您也可以发布一个题为“我很困惑”或“帮助”的问题。您是对的,我已经更改了它。可能是…的副本,或者您可以在后一个函数上使用闭包,如果需要的话。@Phrogz您的意思是在else分支内?@ŠimeVidas Yes;您的答案同样有效,只是对OP进行了注释。另外,请注意,当循环完成时,该值实际上是
-1
,而不是
0
…或者您可以在后一个函数上使用闭包,如果需要的话。@Phrogz您的意思是在else分支内?@imeVidas Yes;您的答案同样有效,只是对OP进行了注释。另外,请注意,当循环结束时,值实际上是
-1
,而不是
0