← Назад к вопросам

Является ли forEach мутирующим методом массива?

1.6 Junior🔥 221 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Является ли forEach мутирующим методом массива?

Ответ: НЕТ, forEach сам по себе не мутирует массив. Однако это может быть запутанным, потому что внутри forEach ты можешь выполнить код, который мутирует массив или объекты. Важно понимать разницу.

Что такое мутация?

Мутация — это изменение оригинального массива или объекта на месте. Мутирующие методы изменяют исходный массив, не создавая новый.

forEach — это итератор. Он НЕ изменяет сам массив (длину, элементы, структуру), но ты можешь использовать его для мутирования других данных.

forEach НЕ мутирует сам массив

const numbers = [1, 2, 3, 4, 5]

// forEach не мутирует сам массив
numbers.forEach(num => {
  // ничего не делаем
})

console.log(numbers)  // [1, 2, 3, 4, 5] — без изменений

Даже если переприсвоить элементы:

const numbers = [1, 2, 3]

numbers.forEach((num, index) => {
  // Это ВСЕ РАВНО мутирует, потому что меняем элемент на месте
  numbers[index] = num * 2  // Мутируем через доступ к индексу
})

console.log(numbers)  // [2, 4, 6] — МУТИРОВАН

Жди! Выше я сказал, что forEach не мутирует, но в примере массив изменился? Объясню подробнее.

Важная разница

forEach сам НЕ имеет встроенной мутации, но:

  1. forEach НЕ создает новый массив — это не map() или filter()
  2. forEach работает с оригинальным массивом — можешь получить доступ через index
  3. Ты можешь мутировать внутри forEach — через array[index] = value или методы объектов

Сравнение: forEach vs map vs filter (мутирующие методы)

Мутирующие методы массива:

const arr = [1, 2, 3]

// ❌ push — мутирует (добавляет элемент)
arr.push(4)
console.log(arr)  // [1, 2, 3, 4]

// ❌ pop — мутирует (удаляет элемент)
arr.pop()
console.log(arr)  // [1, 2, 3]

// ❌ splice — мутирует (вставляет/удаляет)
arr.splice(1, 1, 99)
console.log(arr)  // [1, 99, 3]

// ❌ reverse — мутирует (разворачивает)
arr.reverse()
console.log(arr)  // [3, 99, 1]

// ❌ sort — мутирует (сортирует на месте)
arr.sort((a, b) => a - b)
console.log(arr)  // [1, 3, 99]

// ❌ fill — мутирует (заполняет)
arr.fill(0)
console.log(arr)  // [0, 0, 0]

НЕ мутирующие методы:

const arr = [1, 2, 3]

// ✅ map — НЕ мутирует (создает новый массив)
const doubled = arr.map(x => x * 2)
console.log(arr)  // [1, 2, 3] — без изменений
console.log(doubled)  // [2, 4, 6] — новый массив

// ✅ filter — НЕ мутирует
const evens = arr.filter(x => x % 2 === 0)
console.log(arr)  // [1, 2, 3] — без изменений
console.log(evens)  // [2] — новый массив

// ✅ slice — НЕ мутирует
const sliced = arr.slice(1, 2)
console.log(arr)  // [1, 2, 3] — без изменений
console.log(sliced)  // [2] — новый массив

// ✅ concat — НЕ мутирует
const combined = arr.concat([4, 5])
console.log(arr)  // [1, 2, 3] — без изменений
console.log(combined)  // [1, 2, 3, 4, 5] — новый массив

// ✅ forEach — НЕ мутирует
arr.forEach(x => x * 2)  // Просто итерирует
console.log(arr)  // [1, 2, 3] — без изменений

Когда forEach ВЫГЛЯДИТ как мутирующий?

1. Мутирование элемента через индекс:

const numbers = [1, 2, 3]

// Это мутирует, но мутирует ЧЕРЕЗ forEach (не сам forEach)
numbers.forEach((num, index) => {
  numbers[index] = num * 2  // Мутируем сам массив
})

console.log(numbers)  // [2, 4, 6]

Технически это мутация, но НЕ forEach мутирует — forEach просто дает доступ к индексу. Мутирует код ВНУТРИ forEach.

Правильный способ — использовать map:

const numbers = [1, 2, 3]
const doubled = numbers.map(num => num * 2)
console.log(numbers)  // [1, 2, 3] — оригинал не изменен
console.log(doubled)  // [2, 4, 6] — новый массив

2. Мутирование объектов ВНУТРИ массива:

const users = [
  { name: 'John', age: 30 },
  { name: 'Jane', age: 25 }
]

// forEach работает с ссылками на объекты
users.forEach(user => {
  user.age += 1  // Мутируем объект
})

console.log(users)
// [{ name: 'John', age: 31 }, { name: 'Jane', age: 26 }]
// Объекты изменились! Но это НЕ мутация массива, это мутация объектов

Здесь forEach работает со ССЫЛКАМИ на объекты. Массив сам не изменился (элементы остались на тех же позициях), но объекты внутри изменились.

Правильный способ — использовать map:

const users = [
  { name: 'John', age: 30 },
  { name: 'Jane', age: 25 }
]

const olderUsers = users.map(user => ({
  ...user,
  age: user.age + 1
}))

console.log(users)  // Оригинал не изменен
console.log(olderUsers)  // Новый массив с измененными объектами

forEach vs for loop

const arr = [1, 2, 3]

// forEach — не мутирует сам массив
arr.forEach(item => {
  console.log(item)
})

// for loop — тоже не мутирует
for (let i = 0; i < arr.length; i++) {
  console.log(arr[i])
}

// Оба способа НЕ изменяют массив, но оба могут мутировать данные внутри

Реальный пример: форма с ошибками

const formData = {
  name: '',
  email: '',
  password: ''
}

const errors = []

// ❌ Плохо — forEach для мутации
Object.keys(formData).forEach(key => {
  if (!formData[key]) {
    errors.push(`${key} is required`)  // Мутируем errors массив
  }
})

// ✅ Хорошо — filter для получения новых данных
const errors = Object.keys(formData)
  .filter(key => !formData[key])
  .map(key => `${key} is required`)

Лучшие практики

Используй forEach для:

  • Побочных эффектов (console.log, API запросы, DOM манипуляция)
  • Когда НЕ нужен новый массив
users.forEach(user => {
  console.log(user.name)  // Побочный эффект
  sendEmail(user.email)   // Побочный эффект
})

НЕ используй forEach для:

  • Трансформации данных (используй map)
  • Фильтрации данных (используй filter)
  • Свертки данных (используй reduce)
// ❌ Неправильно
const doubled = []
arr.forEach(x => doubled.push(x * 2))

// ✅ Правильно
const doubled = arr.map(x => x * 2)

Вывод

  1. forEach НЕ мутирует сам массив — это итератор, не изменяет структуру/элементы
  2. Но внутри forEach ты МОЖЕШЬ мутировать — через индекс или объекты
  3. Для трансформации используй map, для фильтрации filter, для свертки reduce
  4. forEach лучше для побочных эффектов — логирования, вызовов функций, DOM манипуляции

Ответ на вопрос: forEach НЕ является мутирующим методом, но он позволяет мутировать внутри себя.