嵌套的jQuery.each() - 继续/中止

45

考虑以下代码:

    var sentences = [
        'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
        'Vivamus aliquet nisl quis velit ornare tempor.',
        'Cras sit amet neque ante, eu ultrices est.',
        'Integer id lectus id nunc venenatis gravida nec eget dolor.',
        'Suspendisse imperdiet turpis ut justo ultricies a aliquet tortor ultrices.'
    ];

    var words = ['ipsum', 'amet', 'elit'];

    $(sentences).each(function() {
        var s = this;
        alert(s);
        $(words).each(function(i) {
            if (s.indexOf(this) > -1)
            {
                alert('found ' + this);
                return false;
            }
        });
    });

有趣的部分是嵌套的jQuery.each()循环。根据文档,返回false将跳出循环(停止执行循环-类似于普通JavaScript break语句),而返回非false将停止当前迭代并继续下一个迭代(类似于普通JavaScript continue语句)。

我可以单独打破或继续使用jQuery.each(),但是在嵌套的jQuery.each中,我发现很难从子循环中退出父循环。我可以使用布尔值,并在每个子迭代中更新它,但我想知道是否有更简单的方法。

如果您想尝试一下,请在jsFiddle上设置示例。只需单击“测试”按钮以运行上面显示的示例即可。

简而言之:在jQuery上下文中是否有类似于标记的continue或break的内容?


2
看起来你在这里过度使用了jQuery,一个简单的for循环就可以实现你想要的效果 :) - Nick Craver
3
这只是一个简化的例子。实际上,我正在循环遍历选中的jQuery DOM节点等等。 - Ryan Kinal
11个回答

94

这里有很多答案。虽然它们已经过时,但对于通过 Google 到达此处的任何人都适用。在 jQuery 的每个函数中,

return false; 就像 break

return; 就像 continue

这些将模拟 break 和 continue 的行为。


1
请查看Serj的回答。它被downvote了,因为你不能有一个带标签的return truereturn false - Ryan Kinal
1
实际上,我在 Firefox 中尝试了返回 true,对我来说它与 break 相同。这就是我的答案原因。 - Thihara
10
这并不会跳出一个嵌套的循环。 - Mr Mikkél

23

你应该不使用jQuery来实现这个功能,虽然可能不太"漂亮",但它能减少代码量,也更容易做到你想要的效果,像这样:

var sentences = [
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
    'Vivamus aliquet nisl quis velit ornare tempor.',
    'Cras sit amet neque ante, eu ultrices est.',
    'Integer id lectus id nunc venenatis gravida nec eget dolor.',
    'Suspendisse imperdiet turpis ut justo ultricies a aliquet tortor ultrices.'
];

var words = ['ipsum', 'amet', 'elit'];

for(var s=0; s<sentences.length; s++) {
    alert(sentences[s]);
    for(var w=0; w<words.length; w++) {
        if(sentences[s].indexOf(words[w]) > -1) {
            alert('found ' + words[w]);
            return;
        }
    }
}

你可以在这里尝试。我不确定这是否是您想要的确切行为,但现在您不再处于由双重.each()创建的闭包内,因此您可以在这种情况下随时使用returnbreak


非常好的观点。即使是在更复杂的jQuery DOM选择器使用中,这也可以正常迭代。 - Ryan Kinal
普通的JavaScript通过了检查。哇,我真喜欢这门语言。 - Ryan Kinal
1
这个解决方案是完全正确的,但它并没有解决所提出的问题。它没有解释如何跳出嵌套的“each”循环链。因此,得分-1(抱歉)。 - Legna
@Legna 是的,它可以... Nick说你可以使用这个解决方案返回(从两个循环中退出)或者break(从内部循环中退出)。 - mhodges

14

1
$(selector).each() VS $.each(set) - 希望它们的功能相同 :) - jave.web

8

没有一种干净的方法可以做到这一点,就像@Nick在上面提到的那样,使用循环的老派方式可能更容易控制。但是,如果你想坚持你得到的东西,有一种方法可以处理这个问题。我肯定会因为这个而受到一些指责。但是...

你可以通过引发错误并用try/catch块包装你的循环来达到你想要的效果,而不需要if语句:

try{
$(sentences).each(function() {
    var s = this;
    alert(s);
    $(words).each(function(i) {
        if (s.indexOf(this) > -1)
        {
            alert('found ' + this);
            throw "Exit Error";
        }
    });
});
}
catch (e)
{
    alert(e)
}

好的,让我们开始折磨吧。


7
哇!这可能是 try/catch 的明显误用,但它有效。 - Ryan Kinal
@Ryan 是的,我知道。这完全违背了我们所学习的做事方式/方法。但我只是试图提出一个解决方案。 - spinon
1
很高兴能帮忙。惊讶的是没有太多的抨击。可能是因为今天比较轻松,或者是我自己意识到这种不太好的做法。 - spinon
差点就给你打了个勾,但感觉太不正经了 :-D 不过说真的,这是个聪明的解决方案。 - Ryan Kinal
1
我也喜欢!这正是为什么我们现在称其为“抛出异常”而不是“引发错误”的原因。只需要将“退出错误”更改为更具外交性的“遇到退出条件”之类的内容,我们就可以洗涤概念并使其符合政治正确性。 :) 可以说(如果倾向于舆论操作),规则是当遇到退出条件时循环“except”,此时抛出异常。 - BobRodes

8
问题在于,尽管你可以在.each回调函数内返回false,但是.each函数本身会返回jQuery对象。因此,你必须在两个级别上都返回false才能停止循环迭代。另外,由于无法知道内部的.each是否找到匹配项,我们将不得不使用闭包中的共享变量进行更新。 words的每个内部迭代都引用相同的notFound变量,因此我们只需要在找到匹配项时更新它,然后返回它。外部闭包已经引用了它,因此可以在需要时break跳出循环。
$(sentences).each(function() {
    var s = this;
    var notFound = true;

    $(words).each(function() {
        return (notFound = (s.indexOf(this) == -1));
    });

    return notFound;
});

您可以在此处尝试示例

8
我已经使用了“分解”模式来实现这个功能:
$(sentences).each(function() {
    var breakout;
    var s = this;
    alert(s);
    $(words).each(function(i) {
        if (s.indexOf(this) > -1)
        {
            alert('found ' + this);
            return breakout = false;
        }
    });
    return breakout;
});

这对于任何嵌套深度都很有效。 `breakout` 是一个简单的标志。除非您将其设置为 `false`(如上面所示的我的返回语句中所做的那样),否则它将保持未定义状态。您需要做的就是:
  1. 在最外层闭包中声明它:var breakout;
  2. 将其添加到您的 return false 语句中:return breakout = false
  3. 在您的外部闭包中返回 `breakout`。
不太粗糙,对吧? ……总之适用于我。

这真的很好,可惜除了被选中的答案之外,所有其他答案都是错误的,却被点赞了。 - bharal

3

return true 不起作用。

return false 起作用。

found = false;
query = "foo";

$('.items').each(function()
{
  if($(this).text() == query)
  {
    found = true;
    return false;
  }
});

3

很遗憾,不行。问题在于迭代发生在函数内部,因此它们不像普通的循环。你可以通过返回或抛出异常来“退出”函数。因此,使用布尔标志似乎是“退出”外部“循环”的唯一合理方式。


2
在API文档http://api.jquery.com/jQuery.each/中确认:

我们可以通过使回调函数返回false来在特定迭代中断$.each()循环。返回非false与for循环中的continue语句相同;它将立即跳到下一个迭代。

这是我的示例http://jsfiddle.net/r6jqP/
(function($){
    $('#go').on('click',function(){
        var i=0,
            all=0;
        $('li').each(function(){
             all++;
             if($('#mytext').val()=='continue')return true;
             i++;
             if($('#mytext').val()==$(this).html()){
                 return false;
             }
        });
        alert('Iterazione : '+i+' to '+all);
    });
}(jQuery));

2

标记式break

outerloop:
$(sentences).each(function() 
{
    $(words).each(function(i) 
    {
        break; /* breaks inner loop */
    } 
    $(words).each(function(i)  
    {
        break outerloop; /* breaks outer loop */
    }
}

它真的有效吗?标记的断点跨越函数边界? - nalply

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接