← Назад к вопросам
Как сделать два разных объекта из одного?
2.0 Middle🔥 161 комментариев
#JavaScript Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как сделать два разных объекта из одного
В JavaScript часто требуется создать копию объекта, но не просто ссылку на исходный объект, а полностью независимый экземпляр. Это критично для предотвращения побочных эффектов и неожиданных изменений данных.
1. Поверхностное копирование (Shallow Copy)
Поверхностная копия копирует только первый уровень свойств. Вложенные объекты остаются ссылками на оригинальные:
// Объект для примеров
const original = {
name: "John",
profile: {
age: 30,
city: "Moscow"
}
};
// Способ 1: Spread оператор
const copy1 = { ...original };
copy1.name = "Jane";
console.log(original.name); // "John" - изменилось не исходное имя
copy1.profile.age = 25;
console.log(original.profile.age); // 25 - ИЗМЕНИЛОСЬ! Вложенный объект - это ссылка
// Способ 2: Object.assign()
const copy2 = Object.assign({}, original);
copy2.name = "Jane";
console.log(original.name); // "John"
// Способ 3: for...in цикл
const copy3 = {};
for (const key in original) {
copy3[key] = original[key];
}
copy3.name = "Jane";
console.log(original.name); // "John"
Поверхностная копия достаточна для простых объектов, но не для вложенных структур.
2. Глубокое копирование (Deep Copy)
Глубокая копия рекурсивно копирует ВСЕ уровни объекта:
Способ 1: JSON (простой, но с ограничениями)
const original = {
name: "John",
profile: {
age: 30,
city: "Moscow"
},
hobbies: ["reading", "coding"],
updated: new Date()
};
// JSON способ - самый быстрый
const deepCopy = JSON.parse(JSON.stringify(original));
deepCopy.name = "Jane";
deepCopy.profile.age = 25;
deepCopy.hobbies.push("gaming");
console.log(original.name); // "John"
console.log(original.profile.age); // 30
console.log(original.hobbies); // ["reading", "coding"]
Минусы JSON подхода:
- Не копирует функции
- Не копирует undefined
- Теряет Date объекты (становятся строками)
- Не копирует Symbol и другие специальные типы
Способ 2: Рекурсивная функция (более гибкий)
function deepCopy(obj) {
// Обработка примитивных типов
if (obj === null || typeof obj !== "object") {
return obj;
}
// Обработка Date
if (obj instanceof Date) {
return new Date(obj.getTime());
}
// Обработка Array
if (obj instanceof Array) {
return obj.map(item => deepCopy(item));
}
// Обработка Object
if (obj instanceof Object) {
const copy = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopy(obj[key]);
}
}
return copy;
}
return obj;
}
// Использование
const original = {
name: "John",
profile: {
age: 30,
updated: new Date("2024-01-01")
},
hobbies: ["reading", "coding"]
};
const copy = deepCopy(original);
copy.profile.updated.setFullYear(2025);
console.log(original.profile.updated.getFullYear()); // 2024 - исходный не изменился
Способ 3: structuredClone() (современный API)
// Встроенный способ в современных браузерах
const original = {
name: "John",
profile: { age: 30, updated: new Date() },
hobbies: ["reading", "coding"]
};
const copy = structuredClone(original);
copy.profile.age = 25;
copy.hobbies.push("gaming");
console.log(original.profile.age); // 30
console.log(original.hobbies); // ["reading", "coding"]
// structuredClone поддерживает Date, Map, Set, ArrayBuffer и другие типы
// Не копирует функции (выбросит ошибку)
3. Копирование с пользовательской логикой
Иногда нужна частичная копия или трансформация:
// Копирование с фильтрацией полей
function copyWithFilter(obj, allowedKeys) {
const copy = {};
allowedKeys.forEach(key => {
if (key in obj) {
copy[key] = obj[key];
}
});
return copy;
}
const user = {
id: 1,
name: "John",
email: "john@example.com",
password: "secret"
};
// Копируем без пароля
const safeCopy = copyWithFilter(user, ["id", "name", "email"]);
console.log(safeCopy); // { id: 1, name: "John", email: "john@example.com" }
// Копирование с трансформацией
function copyWithTransform(obj, transform) {
const copy = { ...obj };
return transform(copy);
}
const transformed = copyWithTransform(user, (copy) => {
copy.name = copy.name.toUpperCase();
return copy;
});
console.log(transformed.name); // "JOHN"
4. Копирование объектов в React
В React часто используют спред оператор для создания новых состояний:
// Текущее состояние
const [user, setUser] = useState({
name: "John",
profile: { age: 30, city: "Moscow" }
});
// Неправильно - изменяет вложенный объект
const handleIncreaseAge = () => {
user.profile.age += 1;
setUser(user); // React не заметит изменение!
};
// Правильно - спред оператор для первого уровня
const handleIncreaseAge = () => {
setUser({
...user,
profile: {
...user.profile,
age: user.profile.age + 1
}
});
};
// Или с structuredClone (в новых приложениях)
const handleIncreaseAge = () => {
const newUser = structuredClone(user);
newUser.profile.age += 1;
setUser(newUser);
};
5. Копирование массивов объектов
const questions = [
{ id: 1, title: "Q1", answers: [{ text: "A1" }] },
{ id: 2, title: "Q2", answers: [{ text: "A2" }] }
];
// Поверхностная копия массива (но объекты внутри - ссылки)
const shallowCopy = [...questions];
shallowCopy[0].title = "New Q1";
console.log(questions[0].title); // "New Q1" - ИЗМЕНИЛОСЬ!
// Глубокая копия массива
const deepCopy = questions.map(q => structuredClone(q));
deepCopy[0].title = "New Q1";
console.log(questions[0].title); // "Q1" - не изменилось
// Или с полной рекурсией
const deepCopy2 = JSON.parse(JSON.stringify(questions));
6. Сравнение производительности
const largeObj = {
level1: { level2: { level3: { level4: { data: [1, 2, 3] } } } }
};
// JSON - БЫСТРО для простых объектов
console.time("JSON");
const copy1 = JSON.parse(JSON.stringify(largeObj));
console.timeEnd("JSON"); // ~0.1ms
// structuredClone - СОВРЕМЕННО и надежно
console.time("structuredClone");
const copy2 = structuredClone(largeObj);
console.timeEnd("structuredClone"); // ~0.2ms
// Рекурсивная функция - ГИБКО, но медленнее
console.time("recursive");
const copy3 = deepCopy(largeObj);
console.timeEnd("recursive"); // ~0.5ms
Когда использовать какой метод
- Spread
{ ...obj }- для простых объектов, первый уровень - JSON методы - для быстрого копирования примитивов и простых структур
- structuredClone() - для современных приложений, полная поддержка типов
- Рекурсивная функция - для кастомной логики и трансформации
- Библиотеки (lodash.cloneDeep) - для критичного функционала
Выбор метода зависит от структуры данных, поддерживаемых браузеров и требуемой функциональности.