break и continue: управление циклом
Здесь будет встроен видео-разбор темы (5–7 минут, YouTube / RuTube / VK Видео) — тем, кто лучше воспринимает на слух, текст ниже не обязателен.
Цикл не обязан честно доходить до конца. break обрывает его целиком, continue отправляет на следующий круг — два коротких слова, которые убирают из кода половину вложенных if.
break — это «хватит». Он немедленно прекращает цикл, внутри которого стоит, и управление уходит на первую строку после цикла. Всё, что осталось в теле итерации ниже break, не выполняется — ни одной строки.
Самое частое применение — поиск. Как только нужное значение найдено, перебирать остаток бессмысленно: массив на миллион элементов не станет быстрее от вежливости.
Второе по частоте применение — цикл, у которого условие выхода живёт не в заголовке, а посередине тела. Тогда заголовок пишут заведомо бесконечным (while (true)), а выход отдают break. Это законный приём, а не признак плохого кода — главное, чтобы выход существовал.
continue не выходит из цикла, а обрывает только текущую итерацию: остаток тела пропускается, и работа продолжается со следующего круга. Для for «следующий круг» означает сначала шаг (i++), потом проверку условия — счётчик не застревает.
Типичная роль continue — фильтр на входе в итерацию: отсеять неподходящее сразу, чтобы полезная работа не оказалась завёрнутой в if на весь экран.
У for шаг счётчика записан в заголовке, и continue его не пропускает. У while шаг делаете вы сами — и если continue стоит раньше строки с увеличением счётчика, до неё уже никогда не дойдёт. Правило простое: сначала двигаем счётчик, потом решаем, пропускать ли итерацию.
break знает только про свой цикл. Из внутреннего он выкинет вас во внешний, а не наружу — и внешний спокойно пойдёт на следующую итерацию. Чтобы указать адрес точнее, циклу дают метку: имя с двоеточием перед словом for или while, а затем пишут break имя.
continue с меткой работает так же адресно: он завершает текущую итерацию помеченного цикла и переводит именно его на следующий шаг. Внутренний цикл при этом просто заканчивается досрочно.
Меткой можно пометить не только цикл, но и обычный блок кода, и выйти из него через break. Но прыгнуть меткой вперёд или назад, как в старом goto, нельзя: метка не место назначения, а имя конструкции, которую вы досрочно закрываете. Поэтому запутать поток управления ею куда сложнее, чем кажется.
Ранний выход — это приём, а не просто оператор: к цепочке if мы прикладывали его в статье «Условия: if, else и тернарный оператор», а внутри цикла ту же работу делает continue. Вместо того чтобы вкладывать условия одно в другое и уводить полезный код на четвёртый уровень отступа, сначала отсеивают всё лишнее короткими continue, а главное действие оставляют на ровном месте — его видно сразу.
Внутри функции ту же работу делает return: он и цикл прерывает, и функцию завершает, сразу отдавая результат. Поэтому связка «break плюс переменная-флаг плюс проверка после цикла» почти всегда разворачивается в одну строку.
Метки в живом коде — редкость. Потянулись за меткой — сначала прикиньте, не проще ли вынести внутренний цикл в функцию и выйти через return.
Сначала общая картина: чем именно отличаются четыре способа прервать ход цикла.
| Оператор | Что прерывает | Что происходит дальше |
|---|---|---|
| break | весь текущий цикл | код сразу после цикла |
| continue | только текущую итерацию | шаг счётчика, затем проверка условия |
| break метка | цикл с этой меткой | код после помеченного цикла |
| continue метка | итерацию помеченного цикла | следующая итерация этого цикла |
| return | цикл и всю функцию | код после вызова функции |
Первая ловушка — switch внутри цикла. Его собственный break закрывает switch, а не цикл: перебор пойдёт дальше как ни в чём не бывало. Чтобы выйти из цикла из ветки case, нужна метка.
Вторая ловушка — методы массивов. Массив умеет перебирать себя сам: forEach и map получают функцию — отдельный кусок кода — и вызывают её для каждого элемента. Цикл при этом спрятан внутри метода, а в вашем коде его нет, поэтому ни break, ни continue в теле такой функции не работают: прервать из неё чужой перебор нельзя. Подробно эти методы разбирает статья «Методы массивов: map, filter, reduce». Выхода из ловушки два: вернуться к for...of или взять метод, который сам умеет останавливаться, — например, find, с которым знакомит статья «Поиск и сортировка». И помните, что break и continue — инструкции, а не значения: в тернарный оператор или в правую часть присваивания их не поставить.
- break прекращает весь цикл: управление сразу переходит на строку после него, остаток итерации пропадает.
- continue обрывает только текущую итерацию; у for шаг счётчика при этом всё равно выполняется, у while его нужно сделать до continue.
- Метка перед циклом (имя с двоеточием) позволяет через break метка или continue метка адресоваться к внешнему циклу, а не к ближайшему.
- Ранние continue и return вместо вложенных if держат код плоским: сначала отсеиваем лишнее, потом делаем главное.
- break внутри switch закрывает switch, а не цикл; в forEach и map break и continue не работают — там нужны find, some, every или обычный for...of.
1/3Что окажется в переменной s? let s = 0; for (let i = 1; i <= 5; i++) { if (i === 3) break; s += i; } console.log(s);
2/3Сработал continue внутри цикла for (let i = 0; i < 3; i++). Что произойдёт дальше?
3/3Внутри for стоит switch, а в одной из его веток — обычный break. Что он прервёт?
Первое число, кратное 7
Найдите в массиве первое число, которое делится на 7 без остатка, и положите его в result. Если такого числа нет, result должен остаться null. Как только число найдено, перебор нужно прекратить.
Классический поиск: проверяем остаток от деления и выходим по первому совпадению.
Без break цикл дошёл бы до конца и записал в result число 35 — последнее подходящее вместо первого. Если вы решаете эту задачу внутри функции, замените break на return n: переменная-накопитель тогда не нужна вовсе.
Пара с суммой 10
Есть два массива. Найдите первую пару чисел (одно из a, другое из b), дающую в сумме 10, и запишите её в pair как массив из двух элементов. Перебор ведите слева направо: сначала все варианты для первого числа из a, потом для второго. Как только пара найдена, оба цикла должны остановиться.
Простой break закрыл бы только внутренний цикл, и внешний продолжил бы работу впустую. Метка выключает оба разом.
Альтернатива без метки — вынести поиск в функцию и выйти через return [x, y]. В реальном коде так и делают чаще: имя функции заодно объясняет, что именно ищется.