ЯдроКодаподготовка к экзаменам
Учебная платформа

Загружаем материалы

Подготавливаем материалы и навигацию по разделу.

Цикл while в JavaScript: условие, завершение и обработка данных

Автор: · Обновлено

Цикл while повторяет действие, пока условие остаётся истинным. Его удобно применять, когда число повторений определяется данными: нужно найти свободное место, разобрать строку…

Цикл while повторяет действие, пока условие остаётся истинным. Его удобно применять, когда число повторений определяется данными: нужно найти свободное место, разобрать строку или обработать записи до специального маркера.

Среда и задача

Примеры выполняются в Node.js 22 или новее: сохраните первый блок в файл while-demo.mjs и запустите node while-demo.mjs. Можно воспользоваться консолью браузера, но не вставляйте туда варианты с намеренно бесконечным циклом. Для урока нужны переменные, массивы и условный оператор if. Слово «пока» описывает условие продолжения, а не паузу или ожидание события.

Представим очередь результатов измерений. Положительное число означает корректное измерение, отрицательное — ошибку датчика, а null завершает текущий пакет. Требуется посчитать сумму корректных результатов до маркера. Значение после маркера принадлежит следующему пакету и обрабатываться не должно. Это полезнее искусственного счётчика: разные входные данные дают разное число проходов, но правило остановки остаётся проверяемым.

Полный пример: пройти пакет и остановиться

const readings = [12, -1, 8, null, 99];
let cursor = 0;
let total = 0;
let accepted = 0;

while (cursor < readings.length) {
  const value = readings[cursor];
  cursor += 1;
  if (value === null) break;
  if (value < 0) continue;
  total += value;
  accepted += 1;
}

console.log(JSON.stringify({ total, accepted, cursor }));

Ожидаемый вывод: {"total":20,"accepted":2,"cursor":4}. На четвёртом проходе программа прочитала маркер и завершила цикл. Число 99 не попало в сумму. Курсор показывает следующую позицию после прочитанного значения; поэтому он равен четырём, хотя принято только два измерения. Разделение этих величин помогает не смешивать просмотренные, пропущенные и принятые записи.

Перед каждым проходом JavaScript вычисляет выражение в круглых скобках. Если оно ложно, тело вообще не выполняется. После последней команды тела управление возвращается к условию. В примере изменение курсора стоит перед возможным continue: даже ошибочное измерение продвигает чтение. Если перенести увеличение в конец тела, отрицательное значение будет встречаться снова и снова. Это типичная причина зависания, которую трудно заметить на массиве только из положительных чисел.

Как обосновать завершение

У цикла должны быть начальное состояние, правило продолжения и изменение состояния. Для нашего алгоритма число оставшихся элементов равно readings.length - cursor. Каждый обычный проход уменьшает его на единицу; break завершает работу ещё раньше. Входной массив во время обхода не растёт. Значит, количество проходов ограничено его исходной длиной. Такая небольшая проверка полезнее надежды на то, что «данные обычно хорошие».

Не любое изменение переменной гарантирует продвижение. Курсор можно случайно уменьшать, сбрасывать в ноль или увеличивать только в одной ветке. Если условие зависит от нескольких переменных, проверьте все пути внутри тела. Для внешнего источника данных нужна отдельная граница: максимальное число страниц, бюджет времени или признак конца. Ограничение должно давать диагностируемую ошибку, иначе молчаливый обрыв выдаст неполный результат за полный.

Условие преобразуется к логическому значению. Поэтому while (array.length) допустимо, но не сообщает, меняется ли массив. А while (value = read()) выполняет присваивание, а не сравнение. Такая конструкция встречается в обходе итераторов, однако начинающему проще отделить чтение от проверки. Явное value !== null также сохраняет допустимые нули: проверка только истинности остановилась бы и на числе 0.

break, continue и do...while

break выходит из ближайшего цикла. Он не завершает весь файл и не возвращает значение из функции. continue пропускает оставшуюся часть текущего прохода и возвращает управление к проверке условия. Если требуется завершить функцию целиком, нужен return; выбор оператора должен соответствовать границе операции, которую вы хотите закончить.

У do...while проверка находится после тела, поэтому тело выполняется минимум один раз. Это подходит для действия, после которого можно решить, требуется ли повторение. Для чтения потенциально пустого массива такое поведение обычно неудобно: первый доступ уже может выйти за границу. Не заменяйте while на do...while ради сокращения строки, не проверив пустой вход. Оба оператора выполняют синхронный код и сами по себе не уступают управление интерфейсу.

Практика с разбором

Напишите функцию takeWithinBudget(costs, budget): она должна принимать расходы по порядку, пока следующий расход помещается в бюджет. Нельзя пропускать дорогой элемент и брать более дешёвый после него. Входные расходы — конечные неотрицательные числа, бюджет такой же; их проверка относится к вызывающему коду. Перед решением разберите пример [4, 7, 2] с бюджетом 10: принять нужно один элемент, остаток составит 6.

function takeWithinBudget(costs, budget) {
  let index = 0;
  let remaining = budget;
  while (index < costs.length && costs[index] <= remaining) {
    remaining -= costs[index];
    index += 1;
  }
  return { count: index, remaining };
}
console.log(JSON.stringify(takeWithinBudget([4, 7, 2], 10)));
console.log(JSON.stringify(takeWithinBudget([], 10)));
console.log(JSON.stringify(takeWithinBudget([0, 0, 3], 0)));

Получатся {"count":1,"remaining":6}, {"count":0,"remaining":10} и {"count":2,"remaining":0}. Последний случай проверяет важную деталь: даже бесплатный расход продвигает индекс. Порядок частей условия защищает доступ к элементу после конца массива. Проверьте также бюджет, точно равный первому расходу: сравнение должно допускать равенство.

Частые вопросы

Почему страница перестала отвечать?

Синхронный цикл занимает поток, пока не завершится. Нельзя ждать клика через while (!clicked): обработчик клика не получит возможности изменить флаг. Остановите выполнение средствами отладчика и проверьте, меняется ли условие. Для пользовательских событий нужен обработчик, для асинхронных операций — соответствующий API.

Почему появился лишний проход?

Сравните < length и <= length, затем распишите индекс до и после тела. Индекс последнего элемента на единицу меньше длины. Отладочная таблица из индекса, текущего значения и суммы обычно показывает ошибку быстрее общего сообщения «неправильный результат».

Когда выбрать for или for...of?

Если нужно посетить все элементы коллекции, for...of часто лучше передаёт намерение. Если рядом важны инициализация, условие и шаг счётчика, удобен for. while особенно понятен там, где продолжение зависит от состояния, а не от заранее выбранного числа повторений.

Источники