Вложенный jQuery.each () - продолжить / прервать

Рассмотрим следующий код:

    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 приведет к выходу из цикла (прекращение выполнения цикла - аналогично обычному оператору break в JavaScript), а возвращение значения, отличного от false, остановит текущую итерацию и продолжит выполнение следующей итерации (аналогично обычному оператору continue в JavaScript).

Я могу прервать или продолжить jQuery.each () самостоятельно, но с вложенным jQuery.each мне было трудно выйти из родительского цикла из дочернего цикла. Я мог бы использовать логическое значение и обновлять его на каждой дочерней итерации, но мне было интересно, есть ли более простой способ.

Я установил пример на jsFiddle, если вы хотите повозиться с ним. Просто нажмите кнопку «Тест», чтобы запустить показанный выше пример.

TL; DR: есть ли что-нибудь похожее на помеченное продолжение или прерывание в контексте jQuery?


person Ryan Kinal    schedule 16.07.2010    source источник
comment
Похоже, вы здесь слишком много используете jQuery, простой цикл for сделает то, что вы хотите :)   -  person Nick Craver    schedule 16.07.2010
comment
Это очень упрощенный пример. На самом деле я перебираю выбранные jQuery узлы DOM и т. Д.   -  person Ryan Kinal    schedule 16.07.2010


Ответы (11)


Вы должны сделать это без 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;
        }
    }
}

Вы можете попробовать это здесь. Я не уверен, что это точное поведение, которое вам нужно, но теперь вы не находитесь в замыкании внутри замыкания, созданного двойным _ 2_, и в этом случае вы можете return или break в любое время.

person Nick Craver    schedule 16.07.2010
comment
Очень хороший момент. Даже при более сложном использовании селекторов jQuery DOM, составляющих мой реальный вариант использования, их можно повторять обычным образом. - person Ryan Kinal; 16.07.2010
comment
Обычный JavaScript проходит проверку. Я люблю этот язык. - person Ryan Kinal; 17.07.2010
comment
это решение безупречно правильное, но оно не решает поставленный вопрос. Он не объясняет, как разорвать цепочку вложенных циклов «каждый». таким образом -1 (извините) - person Legna; 28.10.2015
comment
@Legna Да, это так ... Ник говорит, что вы можете вернуться (выйти из обоих циклов) или прервать (выйти из внутреннего цикла), используя это решение. - person mhodges; 09.04.2016

Здесь много ответов. И он старый, но он предназначен для всех, кто приходит сюда через Google. В jQuery каждая функция

return false; похож на break.

просто

return; похож на continue

Они будут имитировать поведение break и continue.

person Thihara    schedule 11.10.2012
comment
См. Ответ Сержа. Он отклонен, потому что у вас не может быть с меткой return true или return false - person Ryan Kinal; 12.10.2012
comment
на самом деле я пробовал return true в firefox, и для меня это было то же самое, что и перерыв. Это причина моего ответа. - person Thihara; 15.10.2012
comment
Это не выходит за рамки вложенного цикла. - person Mr Mikkél; 01.04.2014


Нет чистого способа сделать это, и, как @Nick, упомянутый выше, может быть проще использовать старый школьный способ циклов, так как тогда вы можете контролировать это. Но если вы хотите придерживаться того, что у вас есть, есть один способ справиться с этим. Я уверен, что получу немного тепла за это. Но...

Один из способов сделать то, что вы хотите, без оператора if - это вызвать ошибку и заключить цикл в блок try / catch:

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)
}

Ладно, давай начнем взбучку.

person spinon    schedule 16.07.2010
comment
Ух ты. Это может быть вопиющее злоупотребление командой try / catch, но это работает. - person Ryan Kinal; 16.07.2010
comment
@ Райан, да, я знаю. Это полностью противоречит тому, что и как нас учат делать. Но я просто пытался предложить решение. - person spinon; 16.07.2010
comment
Рад помочь тогда. Удивил не особо никакой трёпки. Сегодня должно быть светло, или я сам признаю не лучший подход. - person spinon; 16.07.2010
comment
Почти дал вам чек на этот, но он казался слишком грязным :-D А если серьезно, то умное решение. - person Ryan Kinal; 17.07.2010
comment
Мне тоже это нравится! Именно поэтому мы сейчас называем это генерацией исключения вместо того, чтобы вызывать ошибку. Достаточно только изменить ошибку выхода на более дипломатичное встреченное условие выхода или что-то в этом роде, и мы отмыли концепцию и сделали ее политкорректной. :) Кто-то может сказать (если кто-то попадает в спин-доктор), что правило здесь состоит в том, что один зацикливается, за исключением случаев, когда встречается условие выхода, и в этот момент генерируется исключение. - person BobRodes; 04.10.2012

Проблема здесь в том, что, хотя вы можете вернуть false из обратного вызова .each, сама функция .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;
});

Вы можете попробовать свой здесь.

person Anurag    schedule 16.07.2010

Я использовал для этого паттерн «прорыва»:

$(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 - простой флаг. Он будет оставаться undefined до тех пор, пока вы не установите его в false (как я это делаю в моем операторе возврата, как показано выше). Все, что вам нужно сделать, это:

  1. объявите это в самом внешнем закрытии: var breakout;
  2. добавьте его в свой return false оператор (-а): return breakout = false
  3. возвратный прорыв в вашем внешнем закрытии (ах).

Не слишком неэлегантно, правда? ... у меня все равно работает.

person joneit    schedule 02.04.2014
comment
это действительно хорошо, жаль, что все остальные ответы, за исключением выбранного, просто неправильные, были поддержаны. - person bharal; 13.10.2018

К сожалению нет. Проблема здесь в том, что итерация происходит внутри функций, поэтому они не похожи на обычные циклы. Единственный способ «вырваться» из функции - это вернуть или выбросить исключение. Так что да, использование логического флага кажется единственным разумным способом «вырваться» из внешнего «цикла».

person casablanca    schedule 16.07.2010

return true не работает

return false работает

found = false;
query = "foo";

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

Подтвердите в документации API http://api.jquery.com/jQuery.each/ скажите:

Мы можем прервать цикл $ .each () на определенной итерации, заставив функцию обратного вызова вернуть false. Возврат non-false аналогичен оператору continue в цикле for; он сразу перейдет к следующей итерации.

и это мой пример 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));
person Leonardo Ciaccio    schedule 15.06.2013

Помеченный перерыв

outerloop:
$(sentences).each(function() 
{
    $(words).each(function(i) 
    {
        break; /* breaks inner loop */
    } 
    $(words).each(function(i)  
    {
        break outerloop; /* breaks outer loop */
    }
}
person capdragon    schedule 15.05.2012
comment
Действительно ли это работает? Маркированные выходы за границы функций? - person nalply; 25.03.2013

Вы можете прервать цикл $.each() на определенной итерации, заставив функцию обратного вызова вернуть false.

Возврат non-false аналогичен оператору continue в цикле for; он сразу перейдет к следующей итерации.

person Mahdi Fallah    schedule 11.03.2020