打破嵌套(for)循环的最佳方法是什么?

Gar*_*hby 397 javascript loops break nested-loops

在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.
         }
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

eph*_*ent 927

就像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
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

如EMCA-262第12.12节中的定义.[MDN Docs]

与C不同,这些标签只能用于continuebreak,因为Javascript没有goto.

  • WTF为什么我没有看到这在我使用JavaScript的3年中被使用过:/ .. (351认同)
  • MDN纯粹基于可读性理由说"避免使用标签".为什么它不"可读"?当然,因为没有人使用它们.但他们为什么不使用它们呢?... (37认同)
  • @JérémyPouyet - 你的投票逻辑是无效的,没有根据.它完美地回答了OP的问题.问题与您对易读性的看法无关.请重新考虑您协助社区的方法. (25认同)
  • @SeantheBean完成.这似乎是更简单的答案,并且不会滥用,因为它只能用于"继续"和"休息". (8认同)
  • @Web_Designer我相信你的评论已经过时了.在MDN文档中没有任何地方说"避免使用标签".请考虑修改或删除您的评论. (7认同)
  • @NielsBom你是对的:它用给定的标签打破了循环.它没有"转到"标签.你本质上是命名一个循环,说我想要摆脱这样的循环. (6认同)
  • 是"打破*标签"吗?它看起来更像是在命名一个带有n个可选嵌套循环的块,然后通过调用break {label}中止"遍历块". (5认同)
  • 我不认为在一个函数中包装会产生更多可维护的代码而不仅仅是几个标签并打破恕我直言.如果你有3或4级深度的多重嵌套循环 - 3或4个单独的意大利面功能会发生什么? (4认同)
  • 这是不好的做法.考虑使用强大的函数中的包装循环来回答.创建更易读和可维护的代码. (3认同)
  • 在我看来,包含在函数中的方式就是用这种方式标记和断开循环的可读性,因为大多数人习惯于在不同的编程语言中使用类似的方法.我现在正在编写大约3年的C#,JavaScript,Java,我发现这种方法比harley.333的答案更具可读性. (3认同)
  • 低估了一个高度赞成的不良做法(即这就像JS中的编程一样).推荐阅读JavaScript The Good Parts,并更新您的答案. (2认同)
  • 除了关于所谓的“最佳实践”的观点,如果我打开另一个程序员的代码,并且他们脱离了嵌套循环,这就是我想看到的答案。那就是我认为可读的内容:我消化某人的代码并使之有意义需要多长时间?加上许多其他人指出的那样,它是高性能的。每天都可以通过其他“更正确” /复杂的解决方案给我这个答案。 (2认同)
  • @GaryWilloughby 请考虑将此作为可接受的答案。如果我理解正确的话,你的反对意见是你“绝对讨厌 GOTO 并认为它们是不好的做法”,这是一个高度主观的原因,并且不太相关,因为标签与“goto”根本不同。该答案的点赞数足以证明这是大多数阅读该问题的人正在寻找的答案。(如果我是一个赌徒,我也敢打赌这意味着大多数人并不认为使用标签是不好的做法。) (2认同)
  • 哈。在我 25 年的 JS 经验中,我还没有遇到过这个——或者不需要它!JS 世界里总有东西值得学习:) (2认同)

swi*_*ams 156

将其包裹在一个函数中然后只是return.

  • for循环上的标签与GOTO完全没有任何共同点**除了它们的语法.它们只是打破外循环的问题.打破最里面的循环你没有任何问题,对吗?那你为什么要打破外环呢? (31认同)
  • IMO,GOTO只要不破坏结构就可以了.但是每个人都自己! (15认同)
  • 我选择接受这个答案,因为它很简单,可以优雅的方式实现.我绝对讨厌GOTO,并认为它们是不好的做法(*可以打开*),Ephemient太接近了.; O) (11认同)
  • 请考虑接受其他答案.如果没有Andrew Hedges评论(谢谢顺便说一句.),我会想:啊,所以javascript没有这个功能.而且我打赌社区中的许多人可能会忽略评论,并认为同样如此. (11认同)
  • 为什么Stack Overflow没有让社区覆盖明显错误的选定答案的功能?:/ (11认同)
  • 抱歉,我不得不投反对票。虽然对于某些情况来说这可能是一个优雅的解决方案,但它并没有回答问题,即使有一个简单的方法可以在 javascript 中做到这一点。 (2认同)

ale*_*emb 82

我有点迟到了,但以下是与语言无关的方法,不使用GOTO /标签或功能包装:

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
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

在好的方面,它自然流动,这应该取悦非GOTO人群.在缺点方面,内部循环需要在终止之前完成当前迭代,因此在某些情况下可能不适用.

  • @Evgeny:虽然一些JavaScript样式指南要求打开括号在同一行上,但是将它放在新行上是不正确的,并且没有解释器模糊地插入分号的危险.ASI的行为定义明确,不适用于此处. (20认同)
  • 只要确保评论这种方法的地狱.现在发生的事情并不是很明显. (9认同)
  • 新颖的方法+1!但是,这对于 `for(var a in b){...}` 或 `for(var a of b){...}` 样式的 for 循环没有帮助。 (3认同)
  • 左括号不应该在新行上,因为js实现可能会在前一行的末尾插入一个冒号. (2认同)
  • 我可能遗漏了一些东西,但是为了解决内部循环必须完成迭代的问题,您是否可以在设置 z 和 y 后立即放入“break”或“continue”?我确实喜欢使用 `for` 循环的条件来踢出的想法。以自己的方式优雅。 (2认同)

zor*_*ord 70

我意识到这是一个非常古老的话题,但由于我的标准方法还没有到来,我想我会把它发布给未来的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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 不,它从两个循环中退出.这是演示[小提琴](http://jsfiddle.net/zmkfY/).无论你设定什么条件,它都会在它满足之后退出. (7认同)
  • 优化是增加休息时间; 设置abort = true后; 并从最终循环中删除!中止条件检查. (4认同)
  • 如果在嵌套循环的第一次迭代中 `condition` 的计算结果为 `true`,你仍然会运行剩下的 10 次迭代,每次都检查 `abort` 值。这不是 10 次迭代的性能问题,但它会出现,例如,10,000。 (2认同)
  • 我喜欢这个,但我认为从一般意义上讲,您会进行很多不必要的处理 - 也就是说,对于每个迭代器的每次迭代,都会评估 `abort` 和表达式。在简单的场景中可能没问题,但对于具有无数次迭代的巨大循环来说可能是一个问题 (2认同)
  • 新颖的方法+1!但是,这对于 `for(var a in b){...}` 或 `for(var a of b){...}` 样式的 for 循环没有帮助。 (2认同)
  • 你们真的在争论检查单个布尔值 10000 次是快还是慢吗?尝试一亿次/叹息 (2认同)

har*_*333 40

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
}
Run Code Online (Sandbox Code Playgroud)

怎么样?:)

  • 如果循环很大,这会增加显着的运行时成本 - 必须通过Javascript解释器/编译器创建函数的新执行上下文(并且在某些时候由GC释放)(或者,这些天的"compreter",两者的混合)每一次. (18认同)
  • 我认为这就是swilliams所得到的 (2认同)
  • 这实际上非常危险,因为一些奇怪的东西可能会发生,你可能没想到.特别是,由于使用var`x`创建的闭包,如果循环中的任何逻辑在稍后的时间点引用x(例如,它定义了一个保存并稍后执行的内部匿名函数),x的值将为无论它在循环的*end*处是什么,而不是函数在其中定义的索引.(续) (2认同)
  • 同样,我认为可读性是完全废话。这比标签更模糊。标签仅被视为“不可读”,因为没有人使用过它们。 (2认同)

小智 36

非常简单

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;}
}
Run Code Online (Sandbox Code Playgroud)


Dra*_*kes 14

如何完全不使用中断,没有中止标志,也没有额外的条件检查.这个版本只是Number.MAX_VALUE在满足条件时抛出循环变量(使它们)并强制所有循环优雅地终止.

// 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
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

对于递减类型的嵌套循环,有一个类似的答案,但是这适用于递增类型的嵌套循环,而不需要考虑简单循环的每个循环的终止值.

另一个例子:

// 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
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


Dan*_*ray 13

以下是打破JavaScript中的嵌套循环的五种方法:

1)将父循环设置为结尾

for (i = 0; i < 5; i++)
{
    for (j = 0; j < 5; j++)
    {
        if (j === 2)
        {
            i = 5;
            break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

2)使用标签

exit_loops:
for (i = 0; i < 5; i++)
{
    for (j = 0; j < 5; j++)
    {
        if (j === 2)
            break exit_loops;
    }
}
Run Code Online (Sandbox Code Playgroud)

3)使用变量

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;
}
Run Code Online (Sandbox Code Playgroud)

4)使用自我执行功能

(function()
{
    for (i = 0; i < 5; i++)
    {
        for (j = 0; j < 5; j++)
        {
             if (j === 2)
                 return;
        }
    }
})();
Run Code Online (Sandbox Code Playgroud)

5)使用常规功能

function nested_loops()
{
    for (i = 0; i < 5; i++)
    {
        for (j = 0; j < 5; j++)
        {
             if (j === 2)
                 return;
        }
    }
}
nested_loops();
Run Code Online (Sandbox Code Playgroud)

  • 示例 4 很漂亮 (4认同)
  • @Wyck 我非常同意!遗憾的是 javascript 并不像 PHP 那样简单地具有语法“break 2;”。没有循环标签,没有函数,没有 if-else 检查,没有循环变量的回火/爆炸 - 只有干净的语法! (2认同)

use*_*030 5

如何将循环推到最终限制

    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;
            }
         }
       }
     }
Run Code Online (Sandbox Code Playgroud)