Learning Book

for...of и for...in

for…of и for…in

for…of — итерация по значениям

for...of работает с любым итерируемым объектом: массивами, строками, Map, Set:

// Массив
const colors = ['красный', 'зелёный', 'синий'];
for (const color of colors) {
  console.log(color); // 'красный', 'зелёный', 'синий'
}

// Строка — по символам
for (const char of 'hello') {
  console.log(char); // 'h', 'e', 'l', 'l', 'o'
}

// Map — по парам [ключ, значение]
const map = new Map([['a', 1], ['b', 2]]);
for (const [key, value] of map) {
  console.log(`${key}: ${value}`); // 'a: 1', 'b: 2'
}

// Set — уникальные значения
const set = new Set([1, 2, 3, 2, 1]);
for (const item of set) {
  console.log(item); // 1, 2, 3
}

Индекс в for…of

Если нужен индекс вместе со значением — используйте entries():

const fruits = ['яблоко', 'банан', 'вишня'];
for (const [index, fruit] of fruits.entries()) {
  console.log(`${index}: ${fruit}`);
  // 0: яблоко, 1: банан, 2: вишня
}

for…in — итерация по ключам объекта

for...in перебирает перечисляемые свойства объекта, включая унаследованные:

const user = { name: 'Иван', age: 25, role: 'admin' };

for (const key in user) {
  console.log(`${key}: ${user[key]}`);
  // name: Иван, age: 25, role: admin
}
for...in перебирает и унаследованные свойства прототипа! Используйте hasOwnProperty() или Object.keys() для безопасной итерации.
// Безопасный вариант
for (const key in obj) {
  if (Object.hasOwn(obj, key)) { // только собственные свойства
    console.log(key, obj[key]);
  }
}

// Лучше: Object.keys() сразу фильтрует собственные свойства
for (const key of Object.keys(obj)) {
  console.log(key, obj[key]);
}

Главное отличие

for...offor...in
Итерирует поЗначениямКлючам/именам свойств
Работает сИтерируемыми (Array, String, Map, Set)Объектами
Включает прототипНетДа (нужна проверка)
const arr = ['a', 'b', 'c'];

for (const val of arr) {
  console.log(val);   // 'a', 'b', 'c' — значения
}

for (const key in arr) {
  console.log(key);   // '0', '1', '2' — индексы как строки!
}

Объект итерируем если у него есть метод Symbol.iterator. Он должен возвращать итератор — объект с методом next().

// Кастомный итерируемый
const range = {
  from: 1,
  to: 5,
  [Symbol.iterator]() {
    let current = this.from;
    const last = this.to;
    return {
      next() {
        if (current <= last) {
          return { value: current++, done: false };
        }
        return { done: true };
      }
    };
  }
};

for (const n of range) {
  console.log(n); // 1, 2, 3, 4, 5
}