6
for( var i=0; i<20; i++) 
    setTimeout(function(){ 
        console.log(">>> "+i); 
    }, i*100);

So, the code above outputs >>> 19 20 times. To keep i at it's iteration value I'm using a closure:

for(var i=0; i<20; i++)(function(i){
    setTimeout(function(){ 
        console.log(">>> "+i); 
    }, i*100);
}(i));

What's the problem? The problem is loop control statements, continue; I can do with return; but for those times when I need break; code gets counter-intuitive when others try to read it.

So what can I do?

Silviu-Marian
  • 10,565
  • 6
  • 50
  • 72
  • I don't understand why `i` is `19` when the timeouts run: shouldn't it be `20` after the loop completes and thus output `>>> 20` 20 times rather than outputting `>>> 19` 20 times? – nnnnnn Jul 20 '12 at 00:58
  • 1
    No, the loop counts from 0 to 19 (i < 20). ;) – Aletheios Jul 20 '12 at 01:02
  • 2
    @Aletheios - The loop doesn't complete until `i` equals `20` and the `i<20` condition is no longer true. So although `i` is never `20` _inside_ the loop it is `20` by the time the timeouts run. [Try it here...](http://jsfiddle.net/RY2KA/) – nnnnnn Jul 20 '12 at 01:04
  • 2
    @Derek and co., this isn't a duplicate, at least not of that question. OP already knows about using closures to fix that other problem and is asking how to integrate a `break` type behaviour into it. I vote to reopen. – nnnnnn Jul 20 '12 at 01:09
  • @nnnnnn - Oops, you're right... Sorry! – Aletheios Jul 20 '12 at 01:17

2 Answers2

3

How about this?

for (var i = 0; i < 20; i++) {
    var action = (function(i){
        setTimeout(function(){ 
            console.log(">>> "+i); 
        }, i*100);

        // break => return false
        // continue => return anything (e.g. true)
        // default => return nothing
        return false;
    })(i);

    if (action !== undefined) {
        if (!action) {
            break;
        }
        else {
            continue;
        }
    }
}

EDIT:
Added "support" for continue statement. This now works somehow like the jQuery.each() loop.

Aletheios
  • 3,960
  • 2
  • 33
  • 46
  • +1. To make it even more obvious (since OP is concerned about others understanding the code) you could rename the `ret` variable to `doBreak` or similar... – nnnnnn Jul 20 '12 at 01:03
  • Well, that's what I thought because it's `for(...)if(function(){}()==='break') break;` but thank God there's only `continue;` and `break;` – Silviu-Marian Jul 20 '12 at 01:15
1

the problem is the code actually is being called after loop when the i variable is 19. you have to use some local variable. to not confuse yourself i will suggest to use another name for closure parameter.

By the way the second version works well

haynar
  • 5,961
  • 7
  • 33
  • 53