---
title: 'Yapısal Kopyalama'
source: 'https://academia.sh/tr/kurslar/javascript-nesne-modeli/yapisal-kopyalama'
course: "JavaScript'te Nesneler ve Fonksiyonlar"
language: tr
updated: '2026-08-17T18:09:49+00:00'
license: 'CC BY-SA 4.0'
---

# Yapısal Kopyalama

Sığ kopyanın paylaştığı başvurular, dizileştirme yoluyla kopyalamanın kayıpları, yapısal klonlamanın kapsamı ve prototip ile tanımlayıcıları koruyan derin kopya.

Önceki derste kopya ile görünüm ayrımı bayt düzeyinde göründü. Aynı soru nesneler için
kursun başından beri açıktı: nesne yayma zinciri kaybetti, `Object.assign` erişimcileri
düz değere çevirdi, `JSON.stringify` yöntemleri ve `Map` içeriğini attı.

Bu ders o soruyu toplu olarak yanıtlar. Üç kopyalama yolu — yayma, dizileştirme yoluyla
gidiş dönüş ve yapısal klonlama — ayrı ayrı incelenir; her birinin neyi taşıdığı ve neyi
düşürdüğü gösterilir. Ardından her ikisini de koruyan bir derin kopya yazılır.

## Sığ Kopyanın Sınırı

Nesne yayma ve `Object.assign`, kaynağın kendi sayılabilir özelliklerini hedefe yazar.
Değer bir nesne ise yazılan şey o nesnenin **başvurusudur**; nesnenin kendisi kopyalanmaz.

```js
const kaynak = {
  sensor: "S-01",
  deger: 21.4,
  kaynakBilgisi: { dosya: "olcum-2.csv", satir: 17 },
  etiketler: ["ham", "sicaklik"],
};

const yayilmis = { ...kaynak };
const atanmis = Object.assign({}, kaynak);

console.log(yayilmis.sensor);
console.log(yayilmis.kaynakBilgisi === kaynak.kaynakBilgisi);
console.log(atanmis.etiketler === kaynak.etiketler);

yayilmis.sensor = "S-99";
yayilmis.kaynakBilgisi.satir = 99;
yayilmis.etiketler.push("degistirildi");

console.log(kaynak.sensor);
console.log(kaynak.kaynakBilgisi.satir);
console.log(kaynak.etiketler.join(","));
console.log(JSON.stringify(kaynak.kaynakBilgisi) === JSON.stringify(yayilmis.kaynakBilgisi));
```

```
S-01
true
true
S-01
99
ham,sicaklik,degistirildi
true
```

Üst düzeydeki alan bağımsızdır: kopyada `sensor` değiştiğinde kaynak etkilenmez. İç
nesneler ise paylaşılır; kopya üzerinden yapılan her değişiklik kaynakta da görünür.
Programlama Temelleri kursundaki Değer ve Referans ile Aktarım dersinde tanıtılan sığ
kopya–derin kopya ayrımı budur.

Değişmezlik Teknikleri dersindeki dondurmanın neden sığ kaldığı da aynı nedendir: her iki
işlem de nesnenin kendi özellikleriyle sınırlıdır, gösterilen nesnelere inmez.

## Dizileştirme Yoluyla Kopyalama

Bir nesneyi metne çevirip geri okumak, tüm iç nesneleri yeniden yaratır. Kayıpları
büyüktür ve bu kayıplar sessizdir.

```js
const kaynak = {
  sensor: "S-01",
  deger: 21.4,
  kayma: undefined,
  olcumAni: new Date(0),
  etiketKumesi: new Set(["ham", "sicaklik"]),
  kalibrasyon: new Map([["S-01", -0.4]]),
  bicimle() {
    return this.sensor;
  },
};

const jsonKopya = JSON.parse(JSON.stringify(kaynak));

console.log(Object.keys(jsonKopya).join(","));
console.log(typeof jsonKopya.bicimle);
console.log("kayma" in jsonKopya);
console.log(typeof jsonKopya.olcumAni);
console.log(jsonKopya.olcumAni);
console.log(JSON.stringify(jsonKopya.etiketKumesi));
console.log(JSON.stringify(jsonKopya.kalibrasyon));

const cevrimli = { sensor: "S-02" };
cevrimli.kendisi = cevrimli;

try {
  JSON.stringify(cevrimli);
} catch (hata) {
  console.log(`cevrim: ${hata.constructor.name}`);
}
```

```
sensor,deger,olcumAni,etiketKumesi,kalibrasyon
undefined
false
string
1970-01-01T00:00:00.000Z
{}
{}
cevrim: TypeError
```

Beş kayıp sıralanabilir. Fonksiyonlar ve `undefined` değerli alanlar tümüyle düşer.
Tarih nesnesi dizgiye dönüşür ve geri okunduğunda tarih değil metin olur. `Set` ve `Map`
içerikleri boş nesneye iner — İleri Koleksiyonlar konusunun ilk dersinde görülen davranış.
Sayılamaz özellikler ve simge anahtarlar da atlanır. Son olarak çevrimsel başvurular hata
yükseltir.

Prototip zinciri de kaybolur: geri okunan nesne her zaman sıradan bir nesnedir. Bu yol
yalnızca veri taşıyan, iç içe geçmiş sade nesneler için uygundur — zaten JSON biçiminin
kapsamı da budur.

## Yapısal Klonlama

Çalışma zamanının sunduğu `structuredClone` işlevi, dizileştirmeden çok daha geniş bir
değer kümesini derin olarak kopyalar ve çevrimleri korur.

```js
class OlcumKaydi {
  constructor(sensor, deger) {
    this.sensor = sensor;
    this.deger = deger;
    this.etiketKumesi = new Set(["ham"]);
    this.olcumAni = new Date(0);
  }
  bicimle() {
    return `${this.sensor}: ${this.deger}`;
  }
}

const kayit = new OlcumKaydi("S-01", 21.4);
kayit.kendisi = kayit;

const kopya = structuredClone(kayit);

console.log(kopya.sensor);
console.log(kopya.kendisi === kopya);
console.log(kopya.etiketKumesi instanceof Set);
console.log(kopya.etiketKumesi.has("ham"));
console.log(kopya.olcumAni instanceof Date);
console.log(kopya.olcumAni.getTime());
console.log(kopya.etiketKumesi === kayit.etiketKumesi);

console.log(Object.getPrototypeOf(kopya) === OlcumKaydi.prototype);
console.log(kopya instanceof OlcumKaydi);
console.log(typeof kopya.bicimle);

try {
  structuredClone({ islev: () => 1 });
} catch (hata) {
  console.log(`islev: ${hata.name}`);
}

const tipli = new Float64Array([21.4, 19.8]);
const tipliKopya = structuredClone(tipli);
console.log(tipliKopya instanceof Float64Array);
console.log(tipliKopya.buffer === tipli.buffer);
```

```
S-01
true
true
true
true
0
false
false
false
undefined
islev: DataCloneError
true
false
```

Kazanımlar açıktır: çevrimsel başvuru korunur — kopyanın kendine dönen alanı kopyayı
gösterir, kaynağı değil. `Set`, `Map`, `Date` ve tipli diziler türleriyle birlikte
kopyalanır ve iç nesneler paylaşılmaz.

Kayıp tektir ama bu kursun ekseni açısından belirleyicidir: **prototip zinciri taşınmaz.**
Sekizinci, dokuzuncu ve onuncu satırlar bunu üç ayrı biçimde gösterir — kopyanın prototipi
sınıfın prototipi değildir, tür sorgusu olumsuzdur ve yöntem bulunamaz. Sınıf örneği
kopyalandığında geriye yalnızca veri kalır.

Fonksiyonlar da kopyalanamaz ve hata yükseltir. Bu iki sınır aynı gerekçeden gelir:
yapısal klonlama, değerleri başka bir yürütme bağlamına aktarabilmek için tanımlanmıştır;
kod ve zincir aktarılamayacak şeylerdir.

## Zinciri ve Tanımlayıcıları Koruyan Kopya

Hem derinlik hem zincir gerekiyorsa kopya elle yazılmalıdır. Kalıp, Değişmezlik Teknikleri
dersindeki derin dondurmanın kardeşidir: özyinelemeli gezinti, çevrimler için ziyaret
tablosu ve her düğümde prototipin yeniden kurulması.

```js
function derinKopyala(deger, gorulen = new WeakMap()) {
  if (deger === null || typeof deger !== "object") return deger;
  if (gorulen.has(deger)) return gorulen.get(deger);

  if (deger instanceof Date) return new Date(deger.getTime());
  if (deger instanceof Set) {
    const kume = new Set();
    gorulen.set(deger, kume);
    for (const oge of deger) kume.add(derinKopyala(oge, gorulen));
    return kume;
  }
  if (deger instanceof Map) {
    const harita = new Map();
    gorulen.set(deger, harita);
    for (const [anahtar, icerik] of deger) {
      harita.set(derinKopyala(anahtar, gorulen), derinKopyala(icerik, gorulen));
    }
    return harita;
  }

  const kopya = Array.isArray(deger)
    ? []
    : Object.create(Object.getPrototypeOf(deger));
  gorulen.set(deger, kopya);

  for (const ad of Reflect.ownKeys(deger)) {
    const tanim = Object.getOwnPropertyDescriptor(deger, ad);
    if ("value" in tanim) tanim.value = derinKopyala(tanim.value, gorulen);
    Object.defineProperty(kopya, ad, tanim);
  }
  return kopya;
}

class OlcumKaydi {
  constructor(sensor, deger) {
    this.sensor = sensor;
    this.deger = deger;
    this.kaynakBilgisi = { dosya: "olcum-2.csv", satir: 17 };
  }
  bicimle() {
    return `${this.sensor}: ${this.deger}`;
  }
}

const kayit = new OlcumKaydi("S-01", 21.4);
kayit.kendisi = kayit;
Object.defineProperty(kayit, "gizliSayac", {
  value: 3,
  enumerable: false,
  writable: true,
  configurable: true,
});

const kopya = derinKopyala(kayit);

console.log(kopya.bicimle());
console.log(kopya instanceof OlcumKaydi);
console.log(kopya.kendisi === kopya);
console.log(kopya.kaynakBilgisi === kayit.kaynakBilgisi);
console.log(kopya.kaynakBilgisi.satir);
console.log(kopya.gizliSayac);
console.log(Object.keys(kopya).join(","));
console.log(Object.getOwnPropertyDescriptor(kopya, "gizliSayac").enumerable);

kopya.kaynakBilgisi.satir = 99;
console.log(kayit.kaynakBilgisi.satir);
```

```
S-01: 21.4
true
true
false
17
3
sensor,deger,kaynakBilgisi,kendisi
false
17
```

Kopya gerçek bir ölçüm kaydıdır: yöntemi çalışır, tür sorgusu olumludur, çevrimi kendine
döner, iç nesnesi bağımsızdır ve sayılamaz alanı bayrağıyla birlikte korunmuştur.
`Reflect.ownKeys` seçimi, simge anahtarların da kapsanmasını sağlar; tanımlayıcının
kopyalanması ise erişimcilerin düz değere düşmesini engeller.

Bu kalıbın sınırları da vardır. Özel alanlar kopyalanamaz — dışarıdan okunamadıkları için
bir kütüphane işlevinin erişimi yoktur. Kapanışta tutulan durum da aynı nedenle taşınmaz.
Genel kural şudur: **kopyalanabilen şey, dışarıdan görülebilen şeydir.**

## Üç Kuruluş Kopyalama Altında

Kurs boyunca ölçüm kaydı üç biçimde kuruldu. Kopyalama, aralarındaki farkı en keskin
biçimde ortaya koyan sınamadır.

```js
function duzKayit(sensor, deger) {
  return {
    sensor,
    deger,
    bicimle() {
      return `${this.sensor}: ${this.deger}`;
    },
  };
}

function kapanisliKayit(sensor, deger) {
  return {
    bicimle() {
      return `${sensor}: ${deger}`;
    },
  };
}

class SinifKayit {
  constructor(sensor, deger) {
    this.sensor = sensor;
    this.deger = deger;
  }
  bicimle() {
    return `${this.sensor}: ${this.deger}`;
  }
}

function denetle(ad, nesne) {
  const yayilmis = { ...nesne };
  let klonSonucu;
  try {
    const klon = structuredClone(nesne);
    klonSonucu = typeof klon.bicimle === "function" ? klon.bicimle() : "davranis yok";
  } catch (hata) {
    klonSonucu = `hata:${hata.name}`;
  }
  const yayilmaSonucu =
    typeof yayilmis.bicimle === "function" ? yayilmis.bicimle() : "davranis yok";
  console.log(`${ad}: json=${JSON.stringify(nesne)}, yayma=${yayilmaSonucu}, klon=${klonSonucu}`);
}

denetle("duz   ", duzKayit("S-01", 21.4));
denetle("kapanis", kapanisliKayit("S-01", 21.4));
denetle("sinif ", new SinifKayit("S-01", 21.4));

const sinifOrnegi = new SinifKayit("S-01", 21.4);
const zincirliKopya = Object.defineProperties(
  Object.create(Object.getPrototypeOf(sinifOrnegi)),
  Object.getOwnPropertyDescriptors(sinifOrnegi),
);
console.log(zincirliKopya.bicimle());
console.log(zincirliKopya instanceof SinifKayit);
```

```
duz   : json={"sensor":"S-01","deger":21.4}, yayma=S-01: 21.4, klon=hata:DataCloneError
kapanis: json={}, yayma=S-01: 21.4, klon=hata:DataCloneError
sinif : json={"sensor":"S-01","deger":21.4}, yayma=davranis yok, klon=davranis yok
S-01: 21.4
true
```

Üç kuruluş üç ayrı davranış gösterir. Düz nesnede veri ve davranış aynı nesnede durduğu
için dizileştirme veriyi alır, yayma davranışı da taşır, yapısal klonlama ise fonksiyon
yüzünden hata verir. Kapanışlı kuruluşta veri hiç özellik olmadığı için dizileştirme boş
çıkar; yayma yalnızca fonksiyonu kopyalar ve fonksiyon kendi kapanışını taşıdığı için
sonuç yine doğrudur.

Sınıf kuruluşunda ise veri ile davranış ayrı yerlerdedir: veri örnekte, davranış zincirde.
Her iki kopyalama yolu da yalnızca örneği aldığı için davranış düşer — ama hata da vermez.
Zincir gerekiyorsa son iki satırdaki gibi açıkça kurulmalıdır.

Kursun ilk dersindeki cümle burada kapanır: **bir nesnenin verisi kendisinde, kimliği
zincirindedir.** Kopyalama işlemleri kendi özellikleri taşır; zincir ancak açıkça
kurulduğunda taşınır.

## Özet

- Sığ kopya yalnızca üst düzey alanları ayırır; iç nesneler kaynakla paylaşılır.
- Dizileştirme yoluyla kopyalama fonksiyonları, `undefined` alanları, sayılamaz ve simge
  anahtarlı özellikleri düşürür; `Set`, `Map` ve `Date` türlerini bozar, çevrimlerde hata
  verir.
- `structuredClone` çevrimleri korur ve pek çok yerleşik türü türüyle birlikte kopyalar,
  ancak prototip zincirini taşımaz ve fonksiyonlarda hata yükseltir.
- Zinciri ve tanımlayıcıları koruyan kopya elle yazılır: her düğümde prototip yeniden
  kurulur, tanımlayıcılar aynen aktarılır, çevrimler ziyaret tablosuyla izlenir.
- Özel alanlar ve kapanıştaki durum kopyalanamaz; kopyalanabilen şey dışarıdan görülebilen
  şeydir.

## Kurs Kapanışı

Kurs tek bir soruyla başladı: hiç yazılmamış bir özellik nasıl bulunuyor? Yanıt, her
nesnenin taşıdığı prototip bağıydı ve bu bağ on yedi ders boyunca ölçüldü. Özellik araması
nesnenin kendisinden başlayıp zincirde ilerledi; yazma işlemi hiç yukarı çıkmadı, hep
gölgeledi. `new` işlecinin yaptığı iş üç satırla yeniden yazıldı. Sınıf sözdiziminin her
satırının hangi prototip işlemine karşılık geldiği aynı sınamalarla gösterildi — sınıf,
zincirin sözdizimsel yüzüdür; altında farklı bir nesne modeli yoktur.

İkinci konu, zincirin yanıtlamadığı soruyu ele aldı. Prototip bir fonksiyonun **nerede
bulunacağını** belirler; `this` ise **hangi veri üzerinde çalışacağını**. İkisi bağımsız
olduğu için yöntem nesnesinden koparılabilir, başka bir nesneye ödünç verilebilir ya da
kalıcı biçimde bağlanabilir. Ok fonksiyonları bu dört kuralın dışında kalır ve bağlamı
tanımlandıkları kapsamdan alır. Kapanışlar ise durumu zincire hiç dokunmadan gizleyen
ikinci bir kuruluş yolu sundu.

Üçüncü konu koleksiyonları aynı ölçütlerle inceledi: `Map` anahtar kimliğini korur,
zayıf koleksiyonlar nesnelerin ömrünü uzatmaz, yineleme protokolü zincirde bulunan tek bir
yöntemdir, üreteçler o yöntemi kendileri üretir, tipli diziler ayrı bir zincire sahiptir.
Son ders hepsini kopyalama sınamasından geçirdi.

Ölçüm kaydının üç kuruluşu — düz nesne, fabrika ile kapanış, sınıf — kurs boyunca yan yana
tutuldu ve her yeni kavramda karşılaştırıldı: paylaşım, görünürlük, bağlanma, gizlilik,
dizileştirme ve kopyalama. Aralarında doğru bir seçim yoktur; ölçütler açıktır ve
karşılaştırmalar bu derslerdeki çıktılarla ölçülebilir.

Bir şey eksik kaldı. Bu kurstaki her örnek anında sonuçlandı: her `console.log` çağrısı,
kendinden önceki satır bittikten sonra çalıştı. Ölçümler bir dosyadan ya da ağdan geldiğinde
bu varsayım düşer — sonuç, istendiği anda hazır olmaz. **Eşzamansız JavaScript ve Çalışma
Zamanı** kursu bu durumu ele alır: tek iş parçacıklı yürütme modelini, olay döngüsünün
görev ve mikro görev kuyruklarını, söz tabanlı akışları ve bellek yaşam döngüsünü. Bu
kursta öğrendiğiniz zincir ve bağlam kuralları orada da geçerlidir; değişen tek şey,
kodun **ne zaman** çalıştığıdır.
