Вложенные циклы в JavaScript

Вложенный цикл - это цикл, который находится внутри другого цикла. Внешний цикл делает один шаг, после этого внутренний цикл выполняется полностью. Затем внешний цикл делает следующий шаг, и внутренний снова запускается с начала.

for (let i = 1; i <= 3; i++) {
  for (let j = 1; j <= 2; j++) {
    console.log(i + ':' + j);
  }
}

Результат:

1:1
1:2
2:1
2:2
3:1
3:2

Здесь цикл с i внешний, а цикл с j внутренний.

Что такое вложенные циклы

Вложенные циклы нужны, когда данные устроены в несколько уровней. Например, строки и столбцы таблицы, массив внутри массива, сетка, расписание по дням и часам.

Самая частая схема выглядит так:

for (let i = 0; i < 3; i++) {
  for (let j = 0; j < 2; j++) {
    // тело внутреннего цикла
  }
}

i обычно отвечает за внешний уровень.

j отвечает за внутренний уровень.

Названия i и j не обязательны. Если в коде есть понятные сущности, лучше использовать более говорящие имена.

for (let day = 1; day <= 3; day++) {
  for (let lesson = 1; lesson <= 2; lesson++) {
    console.log('День ' + day + ', урок ' + lesson);
  }
}

Как они выполняются

Главное правило: на каждый один шаг внешнего цикла внутренний цикл проходит все свои шаги.

for (let row = 1; row <= 2; row++) {
  console.log('Строка ' + row);

  for (let column = 1; column <= 3; column++) {
    console.log('Столбец ' + column);
  }
}

Результат:

Строка 1
Столбец 1
Столбец 2
Столбец 3
Строка 2
Столбец 1
Столбец 2
Столбец 3

Когда row равен 1, внутренний цикл выводит столбцы 1, 2 и 3. Потом row становится равен 2, и внутренний цикл снова начинает работу с первого столбца.

Пример с координатами

Вложенные циклы удобно использовать, когда нужно перебрать все сочетания значений.

for (let x = 1; x <= 3; x++) {
  for (let y = 1; y <= 3; y++) {
    console.log('x=' + x + ', y=' + y);
  }
}

Результат:

x=1, y=1
x=1, y=2
x=1, y=3
x=2, y=1
x=2, y=2
x=2, y=3
x=3, y=1
x=3, y=2
x=3, y=3

Внешний цикл отвечает за x, внутренний за y. В итоге получаем все пары координат.

Перебор двумерного массива

Двумерный массив - это массив, внутри которого лежат другие массивы. Например, таблица с оценками.

let scores = [
  [5, 4, 5],
  [3, 4, 4],
  [5, 5, 4]
];

Чтобы перебрать все значения, сначала проходим по внешнему массиву, затем по каждому внутреннему.

let scores = [
  [5, 4, 5],
  [3, 4, 4],
  [5, 5, 4]
];

for (let row of scores) {
  for (let score of row) {
    console.log(score);
  }
}

Сначала в переменную row попадает первый внутренний массив [5, 4, 5]. Затем внутренний цикл перебирает его значения. После этого внешний цикл переходит к следующему массиву.

Если нужны индексы строки и столбца, можно использовать обычные циклы for.

let scores = [
  [5, 4, 5],
  [3, 4, 4],
  [5, 5, 4]
];

for (let row = 0; row < scores.length; row++) {
  for (let column = 0; column < scores[row].length; column++) {
    console.log(row + ':' + column + ' = ' + scores[row][column]);
  }
}

Запись scores[row][column] означает: возьми строку по индексу row, а внутри нее значение по индексу column.

break во вложенном цикле

Во вложенных циклах обычный break останавливает только тот цикл, внутри которого находится.

for (let row = 1; row <= 3; row++) {
  for (let column = 1; column <= 3; column++) {
    if (column === 2) {
      break;
    }

    console.log(row + ':' + column);
  }
}

Результат:

1:1
2:1
3:1

Когда column становится равен 2, внутренний цикл останавливается. Но внешний цикл продолжает работу и переходит к следующей строке.

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

Когда использовать

Вложенные циклы подходят, когда данные имеют понятную вложенную структуру:

1. строки и столбцы таблицы;

2. массивы внутри массива;

3. координаты на поле;

4. все сочетания двух наборов значений.

Если вложенность становится больше двух уровней, код быстро сложнее читать. В таких случаях часто стоит вынести часть логики в функцию или пересмотреть структуру данных.

Итого

1. Вложенный цикл - это цикл внутри другого цикла.

2. На каждый шаг внешнего цикла внутренний цикл выполняется полностью.

3. Вложенные циклы часто используют для таблиц, координат и массивов внутри массивов.

4. Для двумерного массива значение можно получить через две пары квадратных скобок: array[row][column].

5. Обычный break во вложенном цикле останавливает только ближайший цикл.