$ sudo teach IT
МОДУЛЬ 5 · УРОК 5

Перебор коллекций: for...of и for...in

Мы умеем создавать массивы и объекты — теперь научимся их перебирать. Два цикла с похожим синтаксисом, но совершенно разным назначением: один для массивов, другой для объектов.

⏱ ~25 минут 🎓 Для новичков 🔄 Циклы

🔄 Почему обычный for не всегда удобен

Обычный цикл for перебирает массив по индексам:

let fruits = ["яблоко", "банан", "апельсин"];

for (let i = 0; i < fruits.length; i++) {
  console.log(fruits[i]);
}

Это работает, но громоздко. Нужно объявить i, следить за условием, писать fruits[i] вместо просто элемента. JavaScript предлагает более чистый синтаксис для перебора коллекций.

Кроме того, для перебора ключей объекта обычный for вообще не подходит — у объекта нет числовых индексов. Именно для этих задач придуманы for...of и for...in.

🔁 for...of — перебор значений

for...of перебирает значения итерируемой коллекции — массива, строки, Set, Map. На каждой итерации переменная получает текущий элемент.

Синтаксис:

for (let элемент of коллекция) {
  // работаем с элементом
}

Перебор массива

let fruits = ["яблоко", "банан", "апельсин", "манго"];

// for...of: переменная fruit = каждый элемент поочерёдно
for (let fruit of fruits) {
  console.log("Фрукт:", fruit);
}
// Фрукт: яблоко
// Фрукт: банан
// Фрукт: апельсин
// Фрукт: манго

// Практический пример: суммируем числа
let prices = [250, 180, 600, 90, 420];
let total = 0;
for (let price of prices) {
  total += price;
}
console.log("Итого:", total); // 1540

Перебор строки

Строка тоже итерируемая — for...of пройдёт по каждому символу:

let word = "Привет";

for (let char of word) {
  console.log(char);
}
// П
// р
// и
// в
// е
// т

// Считаем гласные в слове
let text = "JavaScript";
let vowels = 0;
for (let char of text.toLowerCase()) {
  if ("aeiouаеёиоуыъьэюя".includes(char)) {
    vowels++;
  }
}
console.log("Гласных:", vowels);

for...of с деструктуризацией

При переборе массива через Object.entries() можно сразу распаковывать пары [ключ, значение]:

let prices = { яблоко: 50, банан: 80, апельсин: 120 };

for (let [fruit, price] of Object.entries(prices)) {
  console.log(`${fruit}: ${price} руб.`);
}
// яблоко: 50 руб.
// банан: 80 руб.
// апельсин: 120 руб.

🔑 for...in — перебор ключей объекта

for...in перебирает ключи объекта. На каждой итерации переменная получает строку — имя свойства.

Синтаксис:

for (let ключ in объект) {
  // ключ — строка (имя свойства)
  // объект[ключ] — значение
}
let settings = {
  theme: "dark",
  language: "ru",
  fontSize: 16,
  notifications: true
};

// for...in перебирает ключи
for (let key in settings) {
  console.log(key + ":", settings[key]);
}
// theme: dark
// language: ru
// fontSize: 16
// notifications: true

// Пример: подсчёт свойств объекта
let count = 0;
for (let key in settings) {
  count++;
}
console.log("Настроек всего:", count); // 4

// Пример: найти все числовые значения
let person = { name: "Дима", age: 25, score: 890, city: "Ростов" };
for (let key in person) {
  if (typeof person[key] === "number") {
    console.log(`${key} = ${person[key]}`);
  }
}
// age = 25
// score = 890

⚖️ for...of vs for...in — разница

for...of
  • Перебирает значения
  • Для массивов, строк, Set, Map
  • Переменная = элемент
  • Не работает с обычными объектами!
for...in
  • Перебирает ключи
  • Для объектов
  • Переменная = строка (имя ключа)
  • Для значения: obj[key]

⚠️ Почему for...in плохо подходит для массивов?

Массив в JS — это тоже объект, просто с числовыми ключами. for...in перечислит их как строки ("0", "1", "2"), а не числа. Хуже того — если к массиву добавили кастомные свойства (arr.myProp = "abc"), for...in перечислит и их. Это редко то, что нужно.

let arr = [10, 20, 30];
arr.customProp = "опасно!";

for (let key in arr) {
  console.log(key); // "0", "1", "2", "customProp" — не то, что ожидали!
}

// Правильно для массива:
for (let item of arr) {
  console.log(item); // 10, 20, 30 — только элементы
}

🧪 Практические примеры

Перебор корзины покупок (массив)

let cart = [
  { name: "Ноутбук", price: 65000, qty: 1 },
  { name: "Мышь", price: 1500, qty: 2 },
  { name: "Коврик", price: 800, qty: 1 }
];

let total = 0;
for (let item of cart) {
  let itemTotal = item.price * item.qty;
  console.log(`${item.name}: ${itemTotal} руб.`);
  total += itemTotal;
}
console.log("Итого:", total, "руб."); // 68800

Перебор настроек (объект)

let config = {
  host: "localhost",
  port: 3000,
  debug: true,
  timeout: 5000,
  version: "2.1.0"
};

// Выводим все настройки в читаемом виде
for (let key in config) {
  console.log(`${key} = ${config[key]}`);
}
// host = localhost
// port = 3000
// debug = true
// timeout = 5000
// version = 2.1.0

// Найти все числовые настройки
let numericKeys = [];
for (let key in config) {
  if (typeof config[key] === "number") {
    numericKeys.push(key);
  }
}
console.log("Числовые настройки:", numericKeys); // ["port", "timeout"]

✅ Итоги урока

  • for...of перебирает значения итерируемых коллекций: массивов, строк, Set, Map
  • for...in перебирает ключи объекта (переменная = строка-ключ)
  • Для массивов — for...of; для объектов — for...in или for...of Object.entries()
  • for...in на массивах опасен: перебирает и числовые индексы, и любые кастомные свойства
  • for...of + Object.entries() = перебор объекта с деструктуризацией [key, value]

Следующий урок: массивы объектов — самая важная структура данных в JavaScript-разработке. 🚀

Тест: for...of и for...in

7 вопросов

Нахождение максимума через for...of

Напишите функцию findMax(arr), которая принимает массив чисел и возвращает максимальное значение, используя цикл for...of. Если массив пустой — верните null.

Фильтрация ключей объекта по типу

Напишите функцию filterKeysByType(obj, type), которая принимает объект и строку с названием типа (например, 'string', 'number', 'boolean') и возвращает массив ключей, значения которых имеют указанный тип. Используйте for...in.