Практические рекомендации по массивам и объектам

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

Не мутировать исходные массивы/объекты

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

❌ Плохо — мутация:

const tasks = ['Почитать', 'Написать код'];

function addTask(task) {
  tasks.push(task); // Изменяем исходный массив!
}

addTask('Сделать уборку');
console.log(tasks); // ['Почитать', 'Написать код', 'Сделать уборку'] — оригинал изменён

✅ Хорошо — создание копии:

const tasks = ['Почитать', 'Написать код'];

function addTask(tasksList, task) {
  return [...tasksList, task]; // Новый массив, оригинал не тронут
}

const updatedTasks = addTask(tasks, 'Сделать уборку');
console.log(tasks);           // ['Почитать', 'Написать код'] — не изменился
console.log(updatedTasks);    // ['Почитать', 'Написать код', 'Сделать уборку']

То же правило для объектов:

❌ Плохо:

const user = { name: 'Анна', theme: 'light' };

function updateTheme(user, theme) {
  user.theme = theme; // Мутируем исходный объект
  return user;
}

✅ Хорошо:

function updateTheme(user, theme) {
  return { ...user, theme }; // Новый объект с обновлённым свойством
}

const newUser = updateTheme(user, 'dark');
console.log(user.theme);  // "light" — не изменился
console.log(newUser.theme); // "dark"

Клонирование поверхностное

Копирование с помощью ..., Array.from(), Object.assign() — это поверхностное клонирование. Оно копирует только первый уровень вложенности.

Пример:

const original = {
  name: 'Анна',
  tasks: ['Задача 1', 'Задача 2']
};

const copy = { ...original };

copy.tasks.push('Задача 3');

console.log(original.tasks); // ['Задача 1', 'Задача 2', 'Задача 3'] — изменился!

Почему? Потому что tasks — это массив, и он передаётся по ссылке. Ссылка скопировалась, но сам массив — один и тот же.

Какие методы делают поверхностное клонирование:

Метод Для чего
[...arr] Копия массива
Array.from(arr) Копия массива
{...obj} Копия объекта
Object.assign({}, obj) Копия объекта

Эти методы безопасны для простых данных. Но если в объекте есть вложенные массивы или объекты — они остаются по ссылке.

Когда использовать поверхностное клонирование:

  • Данные не имеют глубокой вложенности.
  • Вы работаете с плоскими структурами: профиль пользователя, настройки, простые задачи.
  • Вы используете библиотеки вроде Redux, Zustand, где ожидается неизменяемость.

Глубокое клонирование — отдельная тема

Если нужно скопировать вложенные структуры полностью — используйте библиотеки (например, lodash.cloneDeep) или специальные методы. В базовом JavaScript это сложно и неэффективно.

Не используйте JSON.parse(JSON.stringify(obj)) для глубокого клонирования — он ломает функции, undefined, Date, Map, Set, и циклические ссылки.