Функція structuredClone()
structuredClone(), це вбудована функція JavaScript, яка створює глибоку копію (deep clone) будь-якого значення, включно з об'єктами, масивами, Map, Set, датами, RegExp, Blob, File, ArrayBuffer і навіть циклічними посиланнями. Результат, це повністю незалежна копія, а не ще одне посилання на той самий об'єкт.
Теорія
TL;DR
structuredClone(value)повертає новий незалежний глибокий клон значення.- Зберігає
Date,Map,Set,RegExp,Error,ArrayBuffer,Blob,File,undefined,NaN,Infinity. - Коректно обробляє циклічні посилання, на яких
JSON.stringify()кидає помилку. - Не вміє копіювати функції, класи з методами та DOM-елементи, буде
DataCloneError. - Другий аргумент
{ transfer: [...] }дозволяє передати бінарний буфер замість копіювання. - Працює в сучасних браузерах і в Node.js починаючи з версії 17.
Швидкий приклад
const user = {
name: "Tim",
age: 25,
skills: ["JS", "React"],
meta: { active: true },
};
const copy = structuredClone(user);
copy.meta.active = false;
console.log(user.meta.active); // true, оригінал не змінивсяТут structuredClone() створив нову копію, а не посилання на той самий об'єкт, на відміну від поверхневого копіювання через { ...user }, де meta залишилася б спільною.
Синтаксис
const clone = structuredClone(value);value, це те, що потрібно склонувати;- функція повертає новий, повністю скопійований і незалежний об'єкт.
Клонування рекурсивне: кожен вкладений об'єкт, масив чи колекція теж отримує власну копію, тому змінювати клон можна як завгодно глибоко.
Головна відмінність від JSON.parse(JSON.stringify(...))
Раніше для глибокого копіювання часто писали так:
const copy = JSON.parse(JSON.stringify(obj));Але в цього способу багато обмежень:
| Тип даних | JSON метод | structuredClone |
|---|---|---|
Date | перетворюється на рядок | зберігається як Date |
Map, Set | губляться | копіюються |
undefined | зникає | зберігається |
RegExp, Error | губляться | зберігаються |
NaN, Infinity | перетворюються на null | зберігаються |
| Циклічні посилання | помилка | підтримуються |
Тобто structuredClone(), це надійний і безпечний аналог deep clone, який підтримує всі ці типи.
Приклад з циклічними посиланнями
const obj = {};
obj.self = obj; // циклічне посилання
const clone = structuredClone(obj);
console.log(clone.self === clone); // trueРаніше таке клонування просто викликало б помилку. Алгоритм structured clone запам'ятовує вже скопійовані об'єкти, тому повторне входження в той самий вузол перетворюється на посилання всередині копії, а не на нескінченну рекурсію.
Клонування з передачею бінарних даних
У structuredClone є другий аргумент, об'єкт опцій, який дозволяє передати (а не скопіювати) деякі об'єкти, наприклад ArrayBuffer.
const buffer = new ArrayBuffer(8);
const clone = structuredClone(buffer, { transfer: [buffer] });
console.log(buffer.byteLength); // 0, оригінал передано і відключено
console.log(clone.byteLength); // 8, дані тепер у клонаЦе працює схоже на transferable-об'єкти в postMessage: пам'ять не копіюється, а змінює власника, тому операція дешева навіть для великих буферів.
Де працює і підсумок
Функція підтримується в усіх сучасних браузерах і в Node.js, починаючи з версії 17:
structuredClone({ test: true }); // працює в Node.js 17+| Пункт | Опис |
|---|---|
| Що робить | Глибоко клонує значення майже будь-якого типу |
| Повертає | Повну незалежну копію |
| Підтримує | Date, Map, Set, RegExp, ArrayBuffer, циклічні посилання |
| Не підтримує | Функції, DOM-елементи |
| Сумісність | Сучасні браузери та Node.js 17+ |
| Аналог | Безпечна альтернатива JSON.parse(JSON.stringify()) |
Типові помилки
- Очікувати, що скопіюються методи. Функції не клонуються:
structuredClone({ fn() {} })кидаєDataCloneError. Клас перетворюється на звичайний об'єкт із даними без прототипу. - Клонувати DOM-вузли.
structuredClone(document.body)теж кидаєDataCloneError, вузли документа не серіалізуються цим алгоритмом. - Плутати з поверхневою копією.
{ ...obj }іObject.assign({}, obj)копіюють лише верхній рівень, вкладені об'єкти залишаються спільними. - Забувати про прототип. Клон отримує звичайний
Object.prototype, томуcopy instanceof Userдастьfalse. - Розраховувати на збереження геттерів і сеттерів. Вони обчислюються один раз, у клон потрапляє вже готове значення як звичайна властивість.
- Використовувати в старому середовищі. У Node.js 16 і нижче функції немає, там потрібен поліфіл або власна реалізація.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.