A structuredClone nem JSON.stringify: így másolj valódi JavaScript-adatot

A structuredClone() megtartja a Date, Map, Set és körkörös hivatkozások szerkezetét is. Mutatjuk, mikor jobb a JSON-trükknél, és mikor érdemes transferről dönteni.

A JavaScript-objektum „mély másolására” még mindig felbukkan a JSON.parse(JSON.stringify(value)). Egyszerű, adatszerű bemenetnél működni látszik, de közben csendben megváltoztatja az adatot, vagy egyáltalán nem fut le. A globális structuredClone() erre készült: a böngészők és a Node.js ugyanazt a szabványos strukturált szerializálási eljárást használják vele.

Strukturált adatok másolását szemléltető technikai diagram

A névben a clone a fontos: új objektumgráfot kapunk, nem új hivatkozásokat a régi belsejében. Ez különösen state-kezelésnél, workernek átadott üzenetnél, cache-be tett válasznál és tesztadat-előkészítésnél hasznos. Nem univerzális „mindent lemásolok” gomb, viszont ha ismerjük a határait, sokkal jobb alapértelmezés a JSON-trükknél.

A JSON nem adatklónozó formátum

A JSON-nak csak néhány primitív típusa van. Egy Date szöveggé alakul, a Map és a Set tipikusan üres objektummá, az undefined objektumtulajdonságként eltűnik, a körkörös hivatkozás pedig kivételt okoz. BigInt esetén a JSON.stringify() szintén hibával áll le. Ezzel szemben a strukturált klónozás a HTML szabványban definiált algoritmus: bejárja az objektumgráfot és kezeli a már látott elemeket is.

const original = {
  createdAt: new Date('2026-08-07T09:00:00.000Z'),
  roles: new Set(['author', 'editor']),
  lookup: new Map([['draft', 3]]),
};
original.self = original;

const copy = structuredClone(original);

console.assert(copy !== original);
console.assert(copy.createdAt instanceof Date);
console.assert(copy.roles instanceof Set && copy.roles.has('editor'));
console.assert(copy.lookup instanceof Map && copy.lookup.get('draft') === 3);
console.assert(copy.self === copy);

A fenti példa nemcsak értékeket tart meg: a klónban a self saját magára mutat. A Date, RegExp, Map, Set, ArrayBuffer, typed arrayek és több webes érték is támogatott. A pontos, platformonként is bővülő lista az MDN strukturált klónozási összefoglalójában szerepel.

Amit szándékosan nem visz át

Függvényt, DOM-csomópontot és más nem szerializálható értéket nem lehet így klónozni: a hívás DataCloneError kivételt dob. Ez jó korai jelzés arra, hogy a függőségeket vagy a viselkedést próbáljuk adatként továbbadni. Osztálypéldánynál sem a prototípus a cél: a saját tulajdonságok adata másolódik, az eredmény nem az eredeti egyedi osztály prototípusát örökli. A property descriptorok, getterek és setterek sem maradnak meg. Ha egy metódusokkal működő domain-objektum kell a másik oldalon, küldjünk belőle DTO-t, majd ott tudatosan építsük újra.

Ez a különbség a biztonság és a hibakeresés szempontjából is egészséges. Egy API-válasz vagy postMessage()-payload általában adat legyen, ne rejtett prototípuslánc. Node-ban a függvény globálisként is elérhető; a Node dokumentációja ugyanazt a böngészőkből ismert API-t írja le.

Klónozás helyett átruházás

Nagy bináris adatoknál a másolat ára számít. Egy ArrayBuffer átadható a második paraméter transfer listájában. Ilyenkor a bájtok tulajdonjoga az új értékhez kerül, az eredeti buffer pedig leválasztódik: a hossza nulla lesz. Ez az a viselkedés, amelyre workernek küldött, már nem szükséges képadatnál vagy hálózatról olvasott bináris payloadnál érdemes építeni.

const bytes = new Uint8Array([72, 105]).buffer;
const moved = structuredClone({ bytes }, { transfer: [bytes] });

console.assert(bytes.byteLength === 0); // az eredeti használhatatlan
console.log(new TextDecoder().decode(moved.bytes)); // Hi

Az átruházás tehát nem optimalizáló kapcsoló, amelyet automatikusan rá kell kapcsolni mindenre. Az eredeti buffer utána nem tartalék példány. Ha mindkét oldalon szükség van rá, maradjon a normál klónozás; ha a feldolgozás felelőssége tényleg átkerül, a transfer elkerüli a nagy másolatot. A transferelhető objektumok webes kontextusát az MDN Transferable objects oldala részletezi.

Nem minden state-frissítéshez való

A mély klón végigjárja a teljes elérhető adatgráfot, és új értékeket hoz létre. Emiatt rossz csere a célzott, immutable frissítésre: ha egy űrlapstate egyetlen mezője változott, egy új felső objektum és az érintett ág másolata világosabb és kevesebb munkát jelent. A structuredClone() inkább határátlépéskor erős: egy meglévő érték független snapshotja kell, vagy az adat másik futási kontextusba kerül. Ez a különbség különösen sokat számít nagy, gyakran változó kliensoldali state-nél.

Egy hasznos döntési szabály

JSON-t akkor használjunk, ha tényleg JSON-szöveget akarunk tárolni vagy hálózaton küldeni. Két JavaScript-érték közötti adatmásoláshoz előbb a structuredClone()-t érdemes megpróbálni. Ha DataCloneError jön, ne újabb klónozó csomagot keressünk reflexből: sokszor ez mutatja meg, hogy az adatmodellben keveredik az adat és a viselkedés. A határ tudatos meghúzása később a worker-kommunikációt és a szerializálást is egyszerűbbé teszi.

Források

Leave a Reply

Az e-mail címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük