Копирование объектов в JavaScript
- Что значит скопировать объект
- Присваивание не копирует объект
- Копирование через spread
- Копирование через Object.assign()
- Копия и изменение объекта
- Поверхностная копия
- Глубокая копия через structuredClone()
- Что выбрать
- Итого
Копирование объекта нужно, когда мы хотим получить новый объект с такими же свойствами, но не менять исходный.
let user = {
name: 'Анна',
age: 28,
};
let copy = { ...user };
copy.age = 29;
console.log(user.age); // 28
console.log(copy.age); // 29
Объекты относятся к ссылочным типам данных, поэтому с ними важно отличать копию от обычной ссылки.
Что значит скопировать объект
Скопировать объект - значит создать новый объект и перенести в него свойства старого объекта.
let user = {
name: 'Анна',
city: 'Москва',
};
let copy = { ...user };
console.log(copy); // { name: 'Анна', city: 'Москва' }
После этого можно менять копию, не затрагивая исходный объект.
Присваивание не копирует объект
Если просто записать объект в другую переменную, копия не создается.
let user = {
name: 'Анна',
age: 28,
};
let copy = user;
copy.age = 29;
console.log(copy.age); // 29
console.log(user.age); // 29
В переменной copy лежит ссылка на тот же объект. Поэтому изменение через copy видно и в user.
Это нормально для JavaScript, но может удивлять, если ожидать независимую копию.
Копирование через spread
Самый частый способ скопировать простой объект - использовать spread-оператор ….
let user = {
name: 'Анна',
age: 28,
};
let copy = { ...user };
console.log(copy); // { name: 'Анна', age: 28 }
Фигурные скобки создают новый объект, а …user переносит в него свойства из старого объекта.
Такой способ хорошо читается и часто используется в современном коде.
Копирование через Object.assign()
Еще один способ - метод Object.assign().
let user = {
name: 'Анна',
age: 28,
};
let copy = Object.assign({}, user);
console.log(copy); // { name: 'Анна', age: 28 }
Первым аргументом передается объект, в который нужно скопировать свойства. В примере это пустой объект .
Вторым аргументом передается объект, который копируем.
Object.assign({}, user);
В современном коде для простого копирования чаще используют spread, но Object.assign() тоже встречается.
Копия и изменение объекта
Копирование удобно, когда нужно получить обновленный объект и оставить старый без изменений.
let user = {
name: 'Анна',
age: 28,
};
let updatedUser = {
...user,
age: 29,
};
console.log(user.age); // 28
console.log(updatedUser.age); // 29
Сначала в новый объект попадают свойства из user, а потом свойство age перезаписывается новым значением.
Такой подход часто используют, когда данные нельзя менять напрямую.
Поверхностная копия
Spread и Object.assign() создают поверхностную копию объекта.
Если в объекте лежат строки, числа и булевы значения, обычно этого достаточно.
let user = {
name: 'Анна',
age: 28,
};
let copy = { ...user };
copy.name = 'Мария';
console.log(user.name); // Анна
console.log(copy.name); // Мария
Но если внутри объекта есть другой объект, копируется ссылка на него.
let user = {
name: 'Анна',
contacts: {
email: 'anna@example.com',
},
};
let copy = { ...user };
copy.contacts.email = 'new@example.com';
console.log(user.contacts.email); // new@example.com
Объект copy новый, но вложенный объект contacts остался общим для user и copy.
Если нужно изменить вложенный объект независимо, его тоже нужно скопировать.
let user = {
name: 'Анна',
contacts: {
email: 'anna@example.com',
},
};
let copy = {
...user,
contacts: {
...user.contacts,
},
};
copy.contacts.email = 'new@example.com';
console.log(user.contacts.email); // anna@example.com
console.log(copy.contacts.email); // new@example.com
Глубокая копия через structuredClone()
Если нужно скопировать объект вместе с вложенными объектами, можно использовать structuredClone().
let user = {
name: 'Анна',
contacts: {
email: 'anna@example.com',
},
};
let copy = structuredClone(user);
copy.contacts.email = 'new@example.com';
console.log(user.contacts.email); // anna@example.com
console.log(copy.contacts.email); // new@example.com
structuredClone() создает глубокую копию: вложенные объекты тоже становятся новыми объектами.
Но использовать его для каждого копирования не нужно. Для простых объектов чаще достаточно spread. Также structuredClone() не подходит для функций и некоторых специальных значений.
Что выбрать
Для обычного копирования простого объекта чаще всего используют spread.
let copy = { ...object };
Если в проекте уже используют Object.assign(), этот вариант тоже нормальный.
let copy = Object.assign({}, object);
Если нужно скопировать вложенную часть объекта, можно скопировать ее отдельно.
let copy = {
...user,
contacts: {
...user.contacts,
},
};
Если нужна глубокая копия всей структуры, можно рассмотреть structuredClone().
Итого
let copy = objectне копирует объект, а записывает ссылку.{ …object }- частый способ скопировать простой объект.Object.assign({}, object)тоже создает новый объект.- Spread и
Object.assign()создают поверхностную копию. - Вложенные объекты при поверхностном копировании остаются общими.
- Для глубокой копии можно использовать
structuredClone(), если он подходит под задачу.