Правильный способ клонирования JavaScript-объектов
Клонирование JS-объекта - довольно распространенная задача в нашей повседневной жизни. Обсудим методы ее решения.
PS. Для правильного клонирования используйте structuredClone
, так как теперь он доступен в родном JS.
Неглубокое и глубокое клонирование
Сначала обсудим, что такое поверхностное клонирование и глубокое клонирование:
Неглубокое и глубокое клонирование - это два различных подхода к копированию объектов в JavaScript, которые имеют разные характеристики и случаи использования:
Неглубокое клонирование:
При неглубоком клонировании создается новый объект, но при этом копируются только свойства верхнего уровня исходного объекта. Если свойства исходного объекта являются ссылками на другие объекты, то эти ссылки разделяются между исходным и клонированным объектами.
Глубокое клонирование:
При глубоком клонировании создается совершенно новый объект со всеми его свойствами и дублированием вложенных свойств. При этом обеспечивается отсутствие общих ссылок между исходным и клонированным объектами, в результате чего создается полностью независимая копия.
Неглубокое клонирование
1. Object.assign()
Метод Object.assign()
- это лаконичный способ неглубокого клонирования объектов JavaScript. Он создает новый объект и копирует перечисляемые свойства из исходного объекта в новый. Однако следует помнить, что если свойства исходного объекта являются объектами или массивами, то они будут скопированы по ссылке.
const clonedObject = Object.assign({}, originalObject);
2. Оператор spread (ES6)
Оператор spread - это еще один метод неглубокого клонирования объектов, появившийся в ES6. Он предоставляет более современный и лаконичный синтаксис для создания неглубокой копии объекта.
const clonedObject = { ...originalObject };
Глубокое клонирование
3. JSON.parse() and JSON.stringify()
Для создания глубокого клона объекта можно использовать JSON.parse()
и JSON.stringify()
. Этот метод сериализует исходный объект в строку JSON, а затем разбирает ее и создает новый объект. Он отлично подходит для глубокого клонирования, но имеет свои ограничения, например, не работает с функциями, символами и круговыми ссылками.
const clonedObject = JSON.parse(JSON.stringify(originalObject));
4. Структурированный клон
В средах веб-рабочих для клонирования объектов можно использовать метод structuredClone
. Этот метод может работать с более сложными типами данных, но он специфичен для веб-работников.
Сравнение методов глубокого клонирования
Допустим, у вас есть объект со свойством функции:
const originalObject = {
name: "John",
age: 30,
greet: function () {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
},
};
Теперь попробуем клонировать этот объект, используя оба метода: JSON.parse(JSON.stringify())
и structuredClone
.
1. Используем JSON.parse(JSON.stringify())
:
const cloneWithJSON = JSON.parse(JSON.stringify(originalObject));
// Attempt to call the function in the cloned object
cloneWithJSON.greet(); // Throws an error: cloneWithJSON.greet is not a function
Как видно, свойство функции теряется в процессе клонирования. JSON.stringify
сериализует объект в JSON, а JSON.parse
создает новый объект из JSON-представления. Функции не являются валидным JSON, поэтому они опускаются.
2. Используем structuredClone
:
const clonedObject = structuredClone(originalObject);
// Attempt to call the function in the cloned object
clonedObject.greet(); // Works as expected: "Hello, my name is John and I am 30 years old."
При использовании structuredClone
в процессе клонирования сохраняется свойство функции, и ее можно без проблем вызывать на клонированном объекте. Этот метод является более мощным и универсальным при работе со сложными объектами, содержащими несериализуемые свойства.
Заключение
- Для неглубокого клонирования следует использовать оператор spread или
Object.assign()
из-за их простоты. - Если требуется глубокое клонирование, а объект не содержит функций, символов или циклических ссылок, используйте
JSON.parse()
иJSON.stringify()
. - Лучше всего использовать метод
structuredClone
, поскольку он теперь доступен нативно и позволяет клонировать даты, RegExps, карты, наборы, блобы, списки файлов, ImageDatas, разреженные массивы, типизированные массивы.
Спасибо за прочтение!