JavaScript’te Structured Clone: Nesneleri Güvenle Kopyalamak ve Worker’lara Taşımak
structuredClone ile derin kopya, desteklenen tipler, kısıtlar ve Worker/postMessage senaryoları.
Uygulama büyüdükçe “deep copy” ihtiyacı kaçınılmaz oluyor: state kopyalamak, cache’den gelen veriyi güvenle çoğaltmak ya da veriyi Web Worker’a taşımak gibi. Bu noktada yıllardır başvurulan JSON.parse(JSON.stringify(x)) hilesi hem veri kaybettirir hem de bazı tiplerde patlar. Modern tarayıcılar ve Node.js artık yerleşik bir çözüm sunuyor: structuredClone().
structuredClone() nedir?
structuredClone(value) JavaScript değerlerini yapısal olarak klonlar. Aynı zamanda postMessage ile Worker/iframe arasında kullanılan structured clone algorithm’in doğrudan API’sidir.
const original = { a: 1, nested: { b: 2 } };
const copy = structuredClone(original);
copy.nested.b = 99;
console.log(original.nested.b); // 2 (orijinal etkilenmez)
JSON hilesine göre ne kazandırır?
1) Veri kaybı olmadan kopyalama
JSON tabanlı yöntem şu tipleri bozar/atar:
Date→ string olurMap,Set→ kaybolurundefined,Infinity,NaN→ kaybolur/değişir- Döngüsel referans (circular) → hata
structuredClone ise pek çok yerleşik tipi doğru şekilde klonlar:
const data = {
createdAt: new Date(),
ids: new Set([1, 2, 3]),
map: new Map([['k', { v: 1 }]]),
value: NaN,
};
const cloned = structuredClone(data);
console.log(cloned.createdAt instanceof Date); // true
console.log(cloned.ids instanceof Set); // true
console.log(cloned.map instanceof Map); // true
2) Circular referanslarla çalışır
const obj = { name: 'root' };
obj.self = obj;
const cloned = structuredClone(obj);
console.log(cloned.self === cloned); // true
Ne zaman özellikle işinize yarar?
Senaryo: Worker’a veri taşırken kopya garantisi
Worker’lar ana thread’i bloklamadan iş yapmak için ideal. postMessage zaten structured clone kullanır; ama bazen mesajı göndermeden önce güvenli bir kopya almak istersiniz.
// main.js
const worker = new Worker('worker.js', { type: 'module' });
const state = {
user: { id: 1, name: 'Ada' },
permissions: new Set(['read', 'write']),
};
// Göndermeden önce sabit bir snapshot al
const snapshot = structuredClone(state);
worker.postMessage(snapshot);
// state sonradan değişse bile snapshot etkilenmez
state.user.name = 'Changed';
// worker.js
self.onmessage = (e) => {
const snapshot = e.data;
// CPU yoğun işi burada yap
self.postMessage({ ok: true, user: snapshot.user.name });
};
Kısıtlar ve sık düşülen hatalar
1) Fonksiyonlar klonlanamaz
structuredClone({ fn: () => 1 });
// DataCloneError
Çözüm: Fonksiyonu veri olarak taşımayın; davranışı kod tarafında yeniden kurun.
2) DOM node’ları klonlanamaz
structuredClone(document.body); // DataCloneError
Çözüm: DOM yerine “serializable” bir temsil (id, selector, props) gönderin.
3) Class instance’larında prototip beklemeyin
structuredClone genelde veriyi kopyalar; özel sınıfların metotları/prototip zinciri korunmayabilir (ortama göre değişebilir). Güvenli yaklaşım: instance yerine plain object (DTO) klonlamak.
Bonus: Transferables ile kopyalamadan taşıma (performans)
Büyük ArrayBuffer’lar için kopya almak pahalı olabilir. structuredClone ikinci parametreyle transfer yapabilir (buffer sahipliği taşınır, kopyalanmaz):
const buffer = new ArrayBuffer(1024 * 1024);
const view = new Uint8Array(buffer);
view[0] = 42;
const cloned = structuredClone({ buffer }, { transfer: [buffer] });
console.log(buffer.byteLength); // 0 (artık bu tarafta boş)
console.log(new Uint8Array(cloned.buffer)[0]); // 42
Sonuç
structuredClone() modern JavaScript’in “doğru derin kopya” aracıdır: JSON tabanlı yöntemlerin veri kaybını önler, circular referansları destekler ve Worker iletişimiyle doğal uyumludur. Kopyalama ihtiyacınız varsa önce structuredClone’a bakın; performans kritikse transfer seçeneğini değerlendirin.