循环中的javascript闭包 [英] javascript closures in loops

查看:72
本文介绍了循环中的javascript闭包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

//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]);

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

Can sombody explain why it happens? Or maybe an alternative to this pattern? My case is this: I receive an array with messages and I have to handle them in order, one ofter another SYNCHRONOUSLY. The problem is some of the messages require firing a series of animations (jqwuery animate() which is async) and the following messages cannot be handled until the last animation is finished. Since there is no sleep() in javascript I was trying to use such pattern where the message calls the next one after it is finished (in case of animations I simply pass the 'next' function pointer to animate's "complete" callback). Anyway, I wanted to build this 'chain' dynamically but discovered this strange (?) behaviour.

推荐答案

你需要一个闭包来使它工作:

You need a closure to make it work:

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] );

现场演示: http://jsfiddle.net/simevidas/3CDdn/

说明:

问题在于这个函数表达式:

The problem is with this function expression:

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

此函数具有 i 变量。调用此函数时,循环的已经结束, i 的值为 -1 。如果要捕获 i 的当前值(迭代期间的值),则需要一个额外的包装函数。此函数永久捕获 i 的当前值(作为参数)。

This function has a live reference to the i variable. When this function is called, the for loop has long ended and the value of i is -1. If you want to capture the current value of i (the value during the iteration), you need to an additional wrapper function. This function captures the current value of i permanently (as an argument).

这篇关于循环中的javascript闭包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆