664

Is there a way to break from nested loops in Javascript?

//Write the links to the page. for (var x = 0; x < Args.length; x++) { for (var Heading in Navigation.Headings) { for (var Item in Navigation.Headings[Heading]) { if (Args[x] == Navigation.Headings[Heading][Item].Name) { document.write("<a href=\"" + Navigation.Headings[Heading][Item].URL + "\">" + Navigation.Headings[Heading][Item].Name + "</a> : "); break; // <---HERE, I need to break out of two loops. } } } } 
1

18 Answers 18

1511

Just like Perl,

loop1: for (var i in set1) { loop2: for (var j in set2) { loop3: for (var k in set3) { break loop2; // breaks out of loop3 and loop2 } } } 

as defined in EMCA-262 section 12.12. [MDN Docs]

Unlike C, these labels can only be used for continue and break, as Javascript does not have goto.

28
  • 561
    WTF why haven't I seen this being used somewhere in my 3 years with JavaScript :/..
    – Celmaun
    CommentedJul 21, 2012 at 18:17
  • 67
    MDN says "avoid using labels" purely on readability grounds. Why is it not 'readable'? Because nobody uses them, of course. But why don't they use them? ...
    – XML
    CommentedMay 2, 2014 at 20:43
  • 10
    Opinions about supposed 'best practices' aside, if I open up another programmer's code and they're breaking out of a nested loop--this is the answer I want to see. That is what I consider readable: How long does it take me to digest someone's code and make sense of it? Plus as many others have pointed out, it's performant. Give me this answer over any of the other more "correct"/convoluted solutions any day.CommentedOct 5, 2015 at 7:02
  • 10
    @SeantheBean Done. This does seem like the more straightforward answer and not open to abuse because it's only available to continue and break.CommentedNov 12, 2015 at 21:17
  • 63
    @JérémyPouyet - Your logic for down voting is inane and unwarranted. It answer the OP's question perfectly. The question is not concerned with your opinions regarding legibility. Please reconsider your approach to assisting the community.CommentedJan 16, 2017 at 20:01
245

Wrap that up in a function and then just return.

9
  • 16
    I choose to accept this answer because it is simple and can be implemented in an elegant fashion. I absolutely hate GOTO's and consider them bad practice (can open), Ephemient's is too near one. ;o)CommentedOct 8, 2008 at 20:05
  • 18
    IMO, GOTO's are fine as long as they don't break structuring. But to each their own!
    – ephemient
    CommentedOct 10, 2008 at 20:09
  • 55
    Labels on for loops have absolutely nothing in common with GOTO except for their syntax. They are simply a matter to break from outer loops. You do not have any problem with breaking the innermost loop, do you? so why do you have a problem with breaking outer loops?CommentedMar 15, 2014 at 15:12
  • 14
    Please consider accepting the other answer. If not for Andrew Hedges comment (thanks btw.), I would have thought: ah, so javascript does not have that feature. And I bet many in the community might overlook the comment and think just the same.CommentedMar 15, 2014 at 20:38
  • 13
    Why doesn't Stack Overflow have a feature to let the community override the obviously wrong selected answer? :/CommentedAug 26, 2014 at 23:40
105

I'm a little late to the party but the following is a language-agnostic approach which doesn't use GOTO/labels or function wrapping:

for (var x = Set1.length; x > 0; x--) { for (var y = Set2.length; y > 0; y--) { for (var z = Set3.length; z > 0; z--) { z = y = -1; // terminates second loop // z = y = x = -1; // terminate first loop } } } 

On the upside it flows naturally which should please the non-GOTO crowd. On the downside, the inner loop needs to complete the current iteration before terminating so it might not be applicable in some scenarios.

7
  • 3
    the opening brace should not be on new lines, because js implementations may insert a colon in the end of the preceding line.
    – Evgeny
    CommentedSep 20, 2012 at 19:07
  • 29
    @Evgeny: while some JavaScript style guides call for opening braces to go on the same line, it is not incorrect to have it on a new line and there is no danger of the interpreter ambiguously inserting a semicolon. The behavior of ASI is well defined and does not apply here.CommentedMar 6, 2013 at 9:25
  • 11
    Just make sure to comment the hell out of this approach. It's not immediately obvious what's going on here.CommentedNov 4, 2014 at 16:02
  • 3
    I may be missing something, but to get around the problem of the inner loop having to finish that iteration could you put in a break or continue immediately after you set z and y? I do like the idea of using the for loop's conditions to kick out. Elegant in its own way.CommentedDec 7, 2015 at 18:01
  • 3
    +1 for a novel approach! However, this won't help with for(var a in b){...} or for(var a of b){...} style for loops.CommentedNov 10, 2019 at 4:36
91

I realize this is a really old topic, but since my standard approach is not here yet, I thought I post it for the future googlers.

var a, b, abort = false; for (a = 0; a < 10 && !abort; a++) { for (b = 0; b < 10 && !abort; b++) { if (condition) { doSomeThing(); abort = true; } } } 
11
  • 2
    If the condition evaluates to true on the first iteration of the nested loop, you still run through the rest of the 10 iterations, checking the abort value each time. This is not a performance problem for 10 iterations, but it would be with, say, 10,000.
    – Robusto
    CommentedDec 2, 2013 at 14:53
  • 9
    No, it's exiting from both loops. Here is the demonstrating fiddle. No matter what condition you set, it's exiting after it's met.
    – zord
    CommentedDec 2, 2013 at 20:13
  • 7
    Optimization would be to add a break; after setting abort = true; and removing !abort condition check from the final loop.
    – xer21
    CommentedSep 20, 2016 at 15:43
  • 2
    I like this but I think in a general sense you would make lots of unnecessary processing - that is, for each iteration of every iterator evalueate abort and the expression. In simple scenarios that might be fine, but for huge loops with gazillion iterations that could be a problemCommentedDec 11, 2017 at 17:08
  • 2
    +1 for a novel approach! However, this won't help with for(var a in b){...} or for(var a of b){...} style for loops.CommentedNov 10, 2019 at 4:38
68

Quite simple:

var a = [1, 2, 3]; var b = [4, 5, 6]; var breakCheck1 = false; for (var i in a) { for (var j in b) { breakCheck1 = true; break; } if (breakCheck1) break; } 
2
  • 1
    I agree this is actually the best, function one doesn't scale, wrapping all for loops in if also doesn't scale i.e. makes it hard to read and debug....this one is awesome. You can just declare vars loop1, loop2, loop3, and add little statement at the end. Also to break multiple loops you would need to do something like loop1=loop2=false;CommentedApr 9, 2015 at 4:30
  • 1
    I have used this arrangement and it works, without complicating it with useless functions. I only arrived here after searching for something to see if js has break 2; like in php.
    – user4188092
    CommentedJun 14, 2021 at 3:09
62

Here are five ways to break out of nested loops in JavaScript:

1) Set parent(s) loop to the end

for (i = 0; i < 5; i++) { for (j = 0; j < 5; j++) { if (j === 2) { i = 5; break; } } } 

2) Use label

exit_loops: for (i = 0; i < 5; i++) { for (j = 0; j < 5; j++) { if (j === 2) break exit_loops; } } 

3) Use variable

var exit_loops = false; for (i = 0; i < 5; i++) { for (j = 0; j < 5; j++) { if (j === 2) { exit_loops = true; break; } } if (exit_loops) break; } 

4) Use self executing function

(function() { for (i = 0; i < 5; i++) { for (j = 0; j < 5; j++) { if (j === 2) return; } } })(); 

5) Use regular function

function nested_loops() { for (i = 0; i < 5; i++) { for (j = 0; j < 5; j++) { if (j === 2) return; } } } nested_loops(); 
10
  • 4
    @Wyck I can't agree enough! It's a shame javascript does not simply have a syntax break 2; like we have in PHP. No loop labels, no functions, no if-else checks, no tempering with / blasting of loop variables - just clean syntax!CommentedNov 10, 2019 at 6:03
  • 5
    Example 4 is niftyCommentedJan 8, 2020 at 17:28
  • @JayDadhania Sorry, your "clean" and "easy" syntax introduces bugs to our softwares. Explicit is better than implicit. I want to name my labels myself.CommentedJan 10, 2021 at 18:41
  • @EkremDinçel a syntax like break 2; does not exist in JS yet, so how could it introduce bugs? You want to label the loops manually? Sure, go ahead - I never said you shouldn't. Also, I in no way advised to manually label JS loops with 3,2,1 - JS does not allow manual labelling of loops with just numbers as of now. I only wished such a thing was implicitly available. Also, such a statement has been a core part of some very popular languages like PHP, and I haven't come across (m)any posts that "want to label the PHP loops manually because break 2; was hard to re-structure".CommentedJan 11, 2021 at 7:31
  • @JayDadhania It does not introduce bugs in JS for sure, it does not exists. But it would do if it exists, I think I explained a bit wrongly it in the above comment. The implicitly you want is a problem, people would use it if it exists in javascript whether you advise it or not. You are giving PHP as an example for this syntax, I think you should also notice the bad history of PHP. I heard they are fixing some things nowadays but it was a language that has so much spaghetti code in apps written with it for a long time, and there is a reason for that.CommentedJan 11, 2021 at 8:46
44
var str = ""; for (var x = 0; x < 3; x++) { (function() { // here's an anonymous function for (var y = 0; y < 3; y++) { for (var z = 0; z < 3; z++) { // you have access to 'x' because of closures str += "x=" + x + " y=" + y + " z=" + z + "<br />"; if (x == z && z == 2) { return; } } } })(); // here, you execute your anonymous function } 

How's that? :)

7
  • 2
    I figured this is what swilliams was getting atCommentedOct 8, 2008 at 20:13
  • 21
    This adds significant runtime cost if the loop is large - a new execution context for the function must be created (and at some point freed by GC) by the Javascript interpreter/compiler (or, "compreter" these days, a mix of both) EVERY SINGLE TIME.
    – Mörre
    CommentedOct 18, 2011 at 12:29
  • 3
    This is actually quite dangerous because some weird stuff can happen that you may not be expecting. In particular, because of the closure created with var x, if any logic within the loop references x at a later point in time (for example it defines an inner anonymous function that is saved and executed later), the value for x will be whatever it was at the end of the loop, not the index that function was defined during. (cont'd)
    – devios1
    CommentedMay 31, 2012 at 21:57
  • 1
    To get around this, you need to pass x as a parameter to your anonymous function so that it creates a new copy of it, which can then be referenced as a closure since it won't change from that point on. In short, I recommend ephemient's answer.
    – devios1
    CommentedMay 31, 2012 at 21:57
  • 3
    As well, I think the readability thing is complete crap. This is way more vague than a label. Labels are only seen as unreadable because nobody ever uses them.CommentedNov 4, 2014 at 16:01
17

How about using no breaks at all, no abort flags, and no extra condition checks. This version just blasts the loop variables (makes them Number.MAX_VALUE) when the condition is met and forces all the loops to terminate elegantly.

// No breaks needed for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { if (condition) { console.log("condition met"); i = j = Number.MAX_VALUE; // Blast the loop variables } } } 

There was a similar-ish answer for decrementing-type nested loops, but this works for incrementing-type nested loops without needing to consider each loop's termination value for simple loops.

Another example:

// No breaks needed for (var i = 0; i < 89; i++) { for (var j = 0; j < 1002; j++) { for (var k = 0; k < 16; k++) { for (var l = 0; l < 2382; l++) { if (condition) { console.log("condition met"); i = j = k = l = Number.MAX_VALUE; // Blast the loop variables } } } } } 
    4

    There are many excellent solutions above. IMO, if your break conditions are exceptions, you can use try-catch:

    try{ for (var i in set1) { for (var j in set2) { for (var k in set3) { throw error; } } } }catch (error) { } 
    1
    • 1
      This is usually discouraged except for languages that have abstract exception handling such as python, since exceptions are usually costly JS loop increment + ~75%. If readable enough, I guess it's okay for non-libraries.
      – Jiří
      CommentedJan 6, 2023 at 14:48
    3

    If you use Coffeescript, there is a convenient "do" keyword that makes it easier to define and immediately execute an anonymous function:

    do -> for a in first_loop for b in second_loop if condition(...) return 

    ...so you can simply use "return" to get out of the loops.

    1
    • This isn't the same. My original example has three for loops not two.CommentedJul 19, 2017 at 20:23
    2

    I thought I'd show a functional-programming approach. You can break out of nested Array.prototype.some() and/or Array.prototype.every() functions, as in my solutions. An added benefit of this approach is that Object.keys() enumerates only an object's own enumerable properties, whereas "a for-in loop enumerates properties in the prototype chain as well".

    Close to the OP's solution:

     Args.forEach(function (arg) { // This guard is not necessary, // since writing an empty string to document would not change it. if (!getAnchorTag(arg)) return; document.write(getAnchorTag(arg)); }); function getAnchorTag (name) { var res = ''; Object.keys(Navigation.Headings).some(function (Heading) { return Object.keys(Navigation.Headings[Heading]).some(function (Item) { if (name == Navigation.Headings[Heading][Item].Name) { res = ("<a href=\"" + Navigation.Headings[Heading][Item].URL + "\">" + Navigation.Headings[Heading][Item].Name + "</a> : "); return true; } }); }); return res; } 

    Solution that reduces iterating over the Headings/Items:

     var remainingArgs = Args.slice(0); Object.keys(Navigation.Headings).some(function (Heading) { return Object.keys(Navigation.Headings[Heading]).some(function (Item) { var i = remainingArgs.indexOf(Navigation.Headings[Heading][Item].Name); if (i === -1) return; document.write("<a href=\"" + Navigation.Headings[Heading][Item].URL + "\">" + Navigation.Headings[Heading][Item].Name + "</a> : "); remainingArgs.splice(i, 1); if (remainingArgs.length === 0) return true; } }); }); 
      2

      How about pushing loops to their end limits

       for(var a=0; a<data_a.length; a++){ for(var b=0; b<data_b.length; b++){ for(var c=0; c<data_c.length; c++){ for(var d=0; d<data_d.length; d++){ a = data_a.length; b = data_b.length; c = data_b.length; d = data_d.length; } } } } 
      2
      • 1
        I think Drakes answer has the same logic in a more succinct and clear manner.CommentedNov 9, 2017 at 17:02
      • absolutely brilliant!
        – geoyws
        CommentedDec 26, 2017 at 20:23
      2

      Already mentioned previously by swilliams, but with an example below (Javascript):

      // Function wrapping inner for loop function CriteriaMatch(record, criteria) { for (var k in criteria) { if (!(k in record)) return false; if (record[k] != criteria[k]) return false; } return true; } // Outer for loop implementing continue if inner for loop returns false var result = []; for (var i = 0; i < _table.length; i++) { var r = _table[i]; if (!CriteriaMatch(r[i], criteria)) continue; result.add(r); } 
        1

        Hmmm hi to the 10 years old party ?

        Why not put some condition in your for ?

        var condition = true for (var i = 0 ; i < Args.length && condition ; i++) { for (var j = 0 ; j < Args[i].length && condition ; j++) { if (Args[i].obj[j] == "[condition]") { condition = false } } } 

        Like this you stop when you want

        In my case, using Typescript, we can use some() which go through the array and stop when condition is met So my code become like this :

        Args.some((listObj) => { return listObj.some((obj) => { return !(obj == "[condition]") }) }) 

        Like this, the loop stopped right after the condition is met

        Reminder : This code run in TypeScript

          1

          Assign the values which are in comparison condition

          function test(){ for(var i=0;i<10;i++) { for(var j=0;j<10;j++) { if(somecondition) { //code to Break out of both loops here i=10; j=10; } } } //Continue from here 

          }

            0

            An example with for .. of, close to the example further up which checks for the abort condition:

            test() function test() { var arr = [1, 2, 3,] var abort = false; for (var elem of arr) { console.log(1, elem) for (var elem2 of arr) { if (elem2 == 2) abort = true; if (!abort) { console.log(2, elem2) } } } } 
            • Condition 1 - outer loop - will always run
            • The top voted and accepted answer also works for this kind of for loop.

            Result: the inner loop will run once as expected

            1 1 2 1 1 2 1 3 
              -3
              XXX.Validation = function() { var ok = false; loop: do { for (...) { while (...) { if (...) { break loop; // Exist the outermost do-while loop } if (...) { continue; // skips current iteration in the while loop } } } if (...) { break loop; } if (...) { break loop; } if (...) { break loop; } if (...) { break loop; } ok = true; break; } while(true); CleanupAndCallbackBeforeReturning(ok); return ok; }; 
              2
              • 9
                This looks more confusing then the original.CommentedOct 11, 2012 at 11:11
              • Voted up because a do while is more becoming to this type of scenario (in most cases).
                – Cody
                CommentedSep 9, 2013 at 14:49
              -5

              the best way is -
              1) Sort the both array which are used in first and second loop.
              2) if item matched then break the inner loop and hold the index value.
              3) when start next iteration start inner loop with hold index value.

                Start asking to get answers

                Find the answer to your question by asking.

                Ask question

                Explore related questions

                See similar questions with these tags.