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

Остается ли у вложенных объектов доступ по ссылке при копировании через spread оператор и Object.assign

2.3 Middle🔥 181 комментариев
#JavaScript Core

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

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

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

Поверхностное копирование в JavaScript

При копировании объектов с помощью spread оператора (...) или Object.assign() создается поверхностная копия (shallow copy). Это означает, что примитивные значения (строки, числа, булевы значения) копируются по значению, а вложенные объекты (включая массивы) копируются по ссылке.

Как работают spread и Object.assign?

Spread оператор:

const original = {
  name: 'John',
  address: {
    city: 'Moscow',
    street: 'Lenina'
  }
};

const copy = { ...original };

// Изменяем вложенный объект в копии
copy.address.city = 'London';

console.log(original.address.city); // 'London' - оригинал тоже изменился!

Object.assign():

const original = {
  data: [1, 2, 3],
  settings: {
    theme: 'dark'
  }
};

const copy = Object.assign({}, original);

// Изменяем вложенный массив
copy.data.push(4);

console.log(original.data); // [1, 2, 3, 4] - изменения в оригинале
console.log(original.settings === copy.settings); // true - одна и та же ссылка

Почему так происходит?

Механизм работы spread и Object.assign заключается в:

  • Создании нового объекта на верхнем уровне
  • Копировании всех собственных перечисляемых свойств
  • Примитивы копируются по значению
  • Объекты (включая массивы, функции, даты) копируются по ссылке

Практические последствия

Проблема мутаций:

const user = {
  id: 1,
  profile: {
    name: 'Anna',
    preferences: {
      notifications: true
    }
  }
};

const updatedUser = { ...user, id: 2 };
updatedUser.profile.preferences.notifications = false;

// Неожиданный побочный эффект:
console.log(user.profile.preferences.notifications); // false

Как это влияет на React/Redux: В Redux редьюсеры должны быть чистыми функциями, возвращающими полностью новые объекты состояния. Поверхностное копирование может привести к скрытым багам:

// ❌ Проблемный код
function reducer(state = initialState, action) {
  switch (action.type) {
    case 'UPDATE_SETTINGS':
      return {
        ...state,
        settings: {
          ...state.settings,
          theme: action.payload
        }
        // А что если в settings есть другие вложенные объекты?
      };
  }
}

Решения для глубокого копирования

  1. Рекурсивная реализация:
function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') return obj;
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof Array) return obj.map(item => deepClone(item));
  
  const cloned = {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloned[key] = deepClone(obj[key]);
    }
  }
  return cloned;
}
  1. JSON методы (с ограничениями):
const deepCopy = JSON.parse(JSON.stringify(original));
// Не копирует функции, undefined, цикличные ссылки
  1. Современные методы:
// structuredClone() - нативная функция для глубокого копирования
const deepCopy = structuredClone(original);
// Поддерживается в современных браузерах

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

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

  • Работаете с плоскими объектами
  • Осознанно хотите разделить ссылки на вложенные объекты
  • Производительность критична

Используйте глубокое копирование когда:

  • Нужна полная изоляция данных
  • Работаете с состоянием в Redux/Vuex
  • Объекты передаются между независимыми модулями

Ключевой вывод: Spread оператор и Object.assign() создают поверхностные копии, где вложенные объекты остаются ссылками на оригинальные объекты. Это важно учитывать при проектировании архитектуры приложения, особенно в контексте управления состоянием и иммутабельных обновлений данных.

Остается ли у вложенных объектов доступ по ссылке при копировании через spread оператор и Object.assign | PrepBro