Signatur
Beschreibung
structuredClone() ist eine globale Funktion und steht in Web Workern, Shared Workern und Service Workern über self bzw. direkt als structuredClone() zur Verfügung. Sie verwendet denselben Structured-Clone-Algorithmus wie postMessage() und legt eine vollständig unabhängige, tiefe Kopie eines Werts an. Verschachtelte Objekte, Arrays, Map, Set, Date, RegExp, ArrayBuffer, typisierte Arrays, Blob, File, ImageData und viele weitere Typen werden dabei korrekt kopiert.
Anders als der verbreitete Trick JSON.parse(JSON.stringify(obj)) bleiben dabei zirkuläre Referenzen und mehrfach referenzierte Unterobjekte erhalten. Auch Datentypen wie Date, Map oder BigInt gehen nicht verloren. Das ist praktisch, wenn ein Worker empfangene Daten verändern will, ohne einen gemeinsamen Zustand anzutasten, oder wenn Zwischenstände (Snapshots) eines Berechnungszustands gespeichert werden sollen.
Mit der Option transfer werden übertragbare Objekte wie ArrayBuffer, MessagePort oder ImageBitmap nicht kopiert, sondern verschoben. Der Klon übernimmt den Speicher, und das Original wird unbrauchbar gemacht (detached). Bei großen Binärdaten spart das Speicher und Rechenzeit.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $value Pflicht | any | Der zu klonende Wert. Das kann ein primitiver Wert oder ein beliebig verschachteltes, strukturiert klonbares Objekt sein. | |
| $options | { transfer?: Transferable[] } | {} | Optionales Objekt. transfer ist ein Array übertragbarer Objekte, die in den Klon verschoben statt kopiert werden. |
Rückgabewert
value. Wirft eine DOMException vom Typ DataCloneError, wenn ein Teil des Werts nicht klonbar ist.Beispiele
Tiefe Kopie im Worker mit Date, Map und zirkulärer Referenz
// worker.js
const state = {
created: new Date('2024-01-01T00:00:00Z'),
cache: new Map([['a', 1]]),
};
state.self = state; // zirkuläre Referenz
const copy = structuredClone(state);
copy.cache.set('b', 2);
console.log(state.cache.size); // Original bleibt unverändert
console.log(copy.created instanceof Date);
console.log(copy.self === copy); // Zirkularität bleibt erhalten
console.log(copy === state);
Empfangene Nachricht unabhängig verarbeiten und Snapshot sichern
// worker.js
const history = [];
self.addEventListener('message', (event) => {
const job = event.data;
// Snapshot des Eingangszustands sichern, bevor er verändert wird
history.push(structuredClone(job));
job.items = job.items.map((n) => n * 2);
job.done = true;
self.postMessage({ result: job, original: history.at(-1) });
});
// main.js
// const worker = new Worker('worker.js');
// worker.onmessage = (e) => console.log(e.data);
// worker.postMessage({ items: [1, 2, 3], done: false });
ArrayBuffer per transfer verschieben statt kopieren
// worker.js
const buffer = new ArrayBuffer(16 * 1024 * 1024); // 16 MB
const moved = structuredClone(buffer, { transfer: [buffer] });
console.log(moved.byteLength); // Speicher gehört jetzt dem Klon
console.log(buffer.byteLength); // Original ist detached
Nicht klonbare Werte abfangen
// worker.js
const config = {
name: 'export',
onDone: () => console.log('fertig'), // Funktionen sind nicht klonbar
};
try {
structuredClone(config);
} catch (err) {
console.log(err.name);
}
// Abhilfe: nur die Daten klonen
const { onDone, ...data } = config;
console.log(structuredClone(data));
// Wichtig · Fallstricke
- Nicht klonbar: Funktionen, DOM-Knoten (in Workern ohnehin nicht vorhanden),
Error-Objekte mit eigenen nicht klonbaren Eigenschaften,WeakMap/WeakSet,Symbolund Proxy-Objekte. Sie lösen einenDataCloneErroraus. - Prototyp geht verloren: Instanzen eigener Klassen werden zu einfachen Objekten. Getter, Setter und Methoden fallen weg, und
instanceof MeineKlasseergibt anschließendfalse. - Property-Deskriptoren (z. B.
writable: false) und Eigenschaften mit Symbol als Schlüssel werden nicht übernommen. BeiRegExpwirdlastIndexnicht mitkopiert. - Nach einem
transferist das Original unbrauchbar: EinArrayBufferhat dannbyteLength === 0, und wer weiter darauf zugreift, bekommt oft einenTypeError. - Performance: Tiefe Kopien großer Strukturen kosten Zeit und Speicher. Große Binärdaten besser per
transferverschieben oderSharedArrayBuffernutzen. Letzteres setzt Cross-Origin-Isolation voraus. - Kompatibilität: Unterstützt seit Chrome/Edge 98, Firefox 94, Safari 15.4 und Node.js 17. Für ältere Umgebungen gibt es Polyfills (z. B. über core-js), die aber nicht alle Typen abdecken.