Перейти к содержимому

structuredClone & Transferables

structuredClone() (глобальная функция с Node.js 17+, браузеры 2022) — нативный deep clone с поддержкой циклических ссылок, Map/Set/Date/RegExp/ArrayBuffer, но без функций и prototype chain; Transferables обеспечивают zero-copy передачу в Worker.

// structuredClone: поддерживаемые типы
const original = {
date: new Date(),
map: new Map([['key', 'value']]),
set: new Set([1, 2, 3]),
regex: /test/gi,
buffer: new ArrayBuffer(8),
typed: new Uint8Array([1, 2, 3]),
error: new Error('msg'), // Node 17.3+ / Chrome 98+
nested: { arr: [1, 2, 3] },
};
original.circular = original; // циклическая ссылка!
const clone = structuredClone(original);
clone.nested.arr.push(4);
console.log(original.nested.arr.length); // 3 — настоящий deep clone
console.log(clone.circular === clone); // true — цикл сохранён
console.log(clone.date === original.date); // false — тоже клонирован
// Что structuredClone НЕ поддерживает:
const bad = {
fn: () => {}, // функции
sym: Symbol('x'), // Symbol values
dom: document.querySelector('div'), // DOM nodes
wm: new WeakMap(), // WeakMap/WeakSet/WeakRef
};
try {
structuredClone(bad);
} catch (e) {
console.log(e.name); // DataCloneError
}
// Prototype chain ТЕРЯЕТСЯ:
class MyPoint { constructor(x,y) { this.x=x; this.y=y; } add(p) {…} }
const p = new MyPoint(1, 2);
const c = structuredClone(p);
console.log(c instanceof MyPoint); // false — plain object!
console.log(typeof c.add); // 'undefined' — методы пропали!
// Для клонирования instances: кастомный serializer или
// Object.assign(Object.create(Object.getPrototypeOf(p)), structuredClone(p))
// Transferable objects: zero-copy transfer (смена ownership)
const buffer = new ArrayBuffer(1024 * 1024); // 1 MB
const view = new Uint8Array(buffer);
view.fill(42);
// postMessage с transfer: buffer передаётся в worker без копирования
const worker = new Worker('./worker.js');
worker.postMessage({ data: buffer }, [buffer]); // transfer!
// ПОСЛЕ transfer: buffer detached — память принадлежит worker
console.log(buffer.byteLength); // 0! Попытка чтения → TypeError
// В worker.js:
// self.onmessage = ({ data: { data } }) => {
// const arr = new Uint8Array(data); // arr.length = 1048576
// self.postMessage({ result: data }, [data]); // вернуть обратно
// };
// Transferable типы: ArrayBuffer, MessagePort, ImageBitmap,
// OffscreenCanvas, ReadableStream, WritableStream, TransformStream
// structuredClone с transfer:
const clone = structuredClone(buffer, { transfer: [buffer] });

Итог: structuredClone — правильный нативный deep clone для сложных объектов с циклами и типизированными массивами; Transferables обеспечивают zero-copy передачу бинарных данных между Workers через смену ownership.