---
title: 'Değişmezlik Teknikleri'
source: 'https://academia.sh/tr/kurslar/javascript-nesne-modeli/degismezlik-teknikleri'
course: "JavaScript'te Nesneler ve Fonksiyonlar"
language: tr
updated: '2026-08-17T18:09:50+00:00'
license: 'CC BY-SA 4.0'
---

# Değişmezlik Teknikleri

Dondurma, mühürleme ve genişletmeyi engelleme işlemlerinin kapsamı, sığ kalmalarının sonuçları, derin dondurma ve değişiklik yerine yeni nesne üretme kalıpları.

Önceki ders tek bir özelliği `writable: false` ile kilitledi. Bir nesnenin bütününü
korumak için her alana ayrı tanım yazmak zahmetlidir ve yeni alan eklenmesini de
engellemez. Dil, nesne düzeyinde çalışan üç işlem sunar.

Bu dersin konusu **değiştirilemezlik (immutability)**: bir nesnenin yaratıldıktan sonra
içeriğinin değişmemesi. Terim, önceki derste geçen *sınıf değişmezi* (invariant) ile
karıştırılmamalıdır; değişmez bir kuraldır, değiştirilemezlik ise bir yetenektir.
Programlama Temelleri kursundaki Fonksiyonel Programlamaya Giriş dersi bu yeteneğin
gerekçesini kurmuştu: değeri değişmeyen bir nesne, kaç yerden başvurulursa başvurulsun
sürprizsizdir.

## Dondurma

`Object.freeze` bir nesnenin tüm kendi özelliklerini yazılamaz ve yapılandırılamaz yapar,
üstelik nesneye yeni özellik eklenmesini de yasaklar.

```js
const kayit = Object.freeze({
  sensor: "S-01",
  deger: 21.4,
  zaman: 1000,
});

console.log(Object.isFrozen(kayit));
console.log(Object.isExtensible(kayit));

const denemeler = [
  ["var olan alani yazma", () => { kayit.deger = 30; }],
  ["yeni alan ekleme", () => { kayit.birim = "santigrat"; }],
  ["alan silme", () => { delete kayit.zaman; }],
  ["tanimi degistirme", () => { Object.defineProperty(kayit, "deger", { value: 30 }); }],
  ["prototip degistirme", () => { Object.setPrototypeOf(kayit, null); }],
];

for (const [ad, islem] of denemeler) {
  try {
    islem();
    console.log(`${ad}: gecti`);
  } catch (hata) {
    console.log(`${ad}: ${hata.constructor.name}`);
  }
}

console.log(JSON.stringify(kayit));
const tanim = Object.getOwnPropertyDescriptor(kayit, "deger");
console.log(`yazilabilir=${tanim.writable}, yapilandirilabilir=${tanim.configurable}`);
```

```
true
false
var olan alani yazma: TypeError
yeni alan ekleme: TypeError
alan silme: TypeError
tanimi degistirme: TypeError
prototip degistirme: TypeError
{"sensor":"S-01","deger":21.4,"zaman":1000}
yazilabilir=false, yapilandirilabilir=false
```

Beş değiştirme yolu da kapanmıştır; prototip bağı bile sabitlenir. Bu ders bir modül
dosyasında, yani katı kipte çalıştığı için denemeler hata yükseltir. Katı olmayan kipte
aynı işlemler sessizce başarısız olur — önceki dersteki ayrımın aynısı.

Dondurma geri alınamaz. `Object.unfreeze` gibi bir işlem yoktur, çünkü
yapılandırılabilirlik kapandıktan sonra tanımlayıcı bir daha değiştirilemez. Bir nesneyi
dondurmak, o nesne üzerinde verilmiş nihai bir karardır.

## Dondurma Sığdır

`Object.freeze` yalnızca nesnenin **kendi** özelliklerine dokunur. İçerideki nesneler ve
prototipteki tanımlar kapsam dışında kalır.

```js
const olcumDavranisi = {
  bicimle() {
    return `${this.sensor}: ${this.deger}`;
  },
};

const kayit = Object.create(olcumDavranisi);
kayit.sensor = "S-01";
kayit.deger = 21.4;
kayit.kaynak = { dosya: "olcum-2.csv", satir: 17 };
Object.freeze(kayit);

console.log(Object.isFrozen(kayit));
console.log(Object.isFrozen(kayit.kaynak));

kayit.kaynak.satir = 99;
console.log(kayit.kaynak.satir);

olcumDavranisi.bicimle = function () {
  return `[degistirildi] ${this.sensor}`;
};
console.log(kayit.bicimle());
console.log(Object.isFrozen(Object.getPrototypeOf(kayit)));
```

```
true
false
99
[degistirildi] S-01
false
```

İki sızıntı vardır. Birincisi tanıdıktır: kaydın `kaynak` alanı bir başvurudur; donan şey
başvurunun kendisidir, gösterdiği nesne değil. Programlama Temelleri kursundaki Değer ve
Referans ile Aktarım dersindeki sığ kopya tartışmasının aynısıdır.

İkincisi prototiple ilgilidir ve bu kursa özgüdür. Kaydın *prototip bağı* dondurulmuştur
ama *prototip nesnesi* dondurulmamıştır. Zincirdeki bir davranışın değiştirilmesi,
dondurulmuş nesnenin davranışını değiştirir. Nesnenin verisi kadar davranışının da sabit
kalması isteniyorsa prototip nesnesi de ayrıca dondurulmalıdır.

## Üç İşlemin Kapsamı

Dondurma en katı seçenektir; iki gevşek biçimi vardır. `Object.preventExtensions`
yalnızca yeni özellik eklenmesini yasaklar, `Object.seal` buna silmeyi de ekler. Farkı
görmek için üçünü aynı denemelerden geçirmek yeterlidir.

```js
function denetle(ad, nesne) {
  const sonuclar = [];
  try {
    nesne.deger = 30;
    sonuclar.push(`yazma=${nesne.deger === 30 ? "oldu" : "olmadi"}`);
  } catch {
    sonuclar.push("yazma=hata");
  }
  try {
    nesne.birim = "santigrat";
    sonuclar.push(`ekleme=${Object.hasOwn(nesne, "birim") ? "oldu" : "olmadi"}`);
  } catch {
    sonuclar.push("ekleme=hata");
  }
  try {
    delete nesne.sensor;
    sonuclar.push(`silme=${Object.hasOwn(nesne, "sensor") ? "olmadi" : "oldu"}`);
  } catch {
    sonuclar.push("silme=hata");
  }
  console.log(`${ad}: ${sonuclar.join(", ")}`);
}

denetle("acik      ", { sensor: "S-01", deger: 21.4 });
denetle("genisletme", Object.preventExtensions({ sensor: "S-01", deger: 21.4 }));
denetle("muhurlu   ", Object.seal({ sensor: "S-01", deger: 21.4 }));
denetle("donmus    ", Object.freeze({ sensor: "S-01", deger: 21.4 }));
```

```
acik      : yazma=oldu, ekleme=oldu, silme=oldu
genisletme: yazma=oldu, ekleme=hata, silme=oldu
muhurlu   : yazma=oldu, ekleme=hata, silme=hata
donmus    : yazma=hata, ekleme=hata, silme=hata
```

Kapsamlar iç içedir: genişletmeyi engelleme ⊂ mühürleme ⊂ dondurma. Mühürleme, alan
kümesi sabit ama değerleri değişebilen nesneler için uygundur — bir yapılandırma kaydının
biçimini kilitleyip içeriğini serbest bırakmak gibi. Dondurma ise nesneyi tümüyle sabit
kılar.

## Derin Dondurma

Sığlığı aşmak için özyinelemeli bir gezinti gerekir. Programlama Temelleri kursundaki
Özyineleme dersinin kalıbı doğrudan uygulanır: taban durumu nesne olmayan değerlerdir,
indirgeme adımı her alanın kendisini dondurmaktır. Çevrimsel başvuruların sonsuz
özyinelemeye yol açmaması için ziyaret edilenler işaretlenir.

```js
function derinDondur(nesne, gorulen = new WeakSet()) {
  if (nesne === null || typeof nesne !== "object" || gorulen.has(nesne)) {
    return nesne;
  }
  gorulen.add(nesne);
  for (const ad of Object.getOwnPropertyNames(nesne)) {
    const tanim = Object.getOwnPropertyDescriptor(nesne, ad);
    if ("value" in tanim) derinDondur(tanim.value, gorulen);
  }
  return Object.freeze(nesne);
}

const kayit = derinDondur({
  sensor: "S-01",
  deger: 21.4,
  kaynak: { dosya: "olcum-2.csv", satir: 17 },
  etiketler: ["ham", "sicaklik"],
});

console.log(Object.isFrozen(kayit));
console.log(Object.isFrozen(kayit.kaynak));
console.log(Object.isFrozen(kayit.etiketler));

try {
  kayit.kaynak.satir = 99;
} catch (hata) {
  console.log(`ic nesne yazma: ${hata.constructor.name}`);
}
try {
  kayit.etiketler.push("yeni");
} catch (hata) {
  console.log(`diziye ekleme: ${hata.constructor.name}`);
}

console.log(JSON.stringify(kayit));
```

```
true
true
true
ic nesne yazma: TypeError
diziye ekleme: TypeError
{"sensor":"S-01","deger":21.4,"kaynak":{"dosya":"olcum-2.csv","satir":17},"etiketler":["ham","sicaklik"]}
```

Diziler de nesne olduğu için aynı işlemden geçer; dondurulmuş bir diziye ekleme yapmak
hata yükseltir. `getOwnPropertyNames` kullanılması sayılamaz alanların da kapsanmasını
sağlar; erişimci özelliklerde `value` alanı bulunmadığından okuyucu fonksiyon
çalıştırılmaz. `WeakSet` seçimi bilinçlidir: işaretleme geçicidir ve gezilen nesnelerin
ömrünü uzatmamalıdır. Bu koleksiyonun ayrıntısı İleri Koleksiyonlar konusundadır.

Derin dondurmanın maliyeti nesne sayısıyla doğru orantılıdır; büyük ağaçlarda her
yaratımda uygulanması pahalıdır. Yaygın uygulama, dondurmayı yalnızca paylaşılan ve uzun
ömürlü verilerde kullanmaktır.

## Değiştirmek Yerine Üretmek

Nesne dondurulduğunda "alanı güncelle" isteği bir soruya dönüşür: güncellenmiş yeni nesne
nasıl üretilir? Nesne yayma bunun için yeterli görünür, ama zincirle ilgili bir bedeli
vardır.

```js
class OlcumKaydi {
  constructor(sensor, deger, zaman) {
    this.sensor = sensor;
    this.deger = deger;
    this.zaman = zaman;
    Object.freeze(this);
  }
  bicimle() {
    return `${this.sensor}@${this.zaman}: ${this.deger}`;
  }
  degerleDegistir(yeniDeger) {
    const kopya = Object.create(Object.getPrototypeOf(this));
    Object.assign(kopya, this, { deger: yeniDeger });
    return Object.freeze(kopya);
  }
}

const ilk = new OlcumKaydi("S-01", 21.4, 1000);
const yayilarak = { ...ilk, deger: 30 };
const yontemle = ilk.degerleDegistir(30);

console.log(ilk.bicimle());
console.log(JSON.stringify(yayilarak));
console.log(typeof yayilarak.bicimle);
console.log(Object.getPrototypeOf(yayilarak) === OlcumKaydi.prototype);
console.log(Object.isFrozen(yayilarak));

console.log(yontemle.bicimle());
console.log(Object.getPrototypeOf(yontemle) === OlcumKaydi.prototype);
console.log(yontemle instanceof OlcumKaydi);
console.log(Object.isFrozen(yontemle));
console.log(ilk.deger);
```

```
S-01@1000: 21.4
{"sensor":"S-01","deger":30,"zaman":1000}
undefined
false
false
S-01@1000: 30
true
true
true
21.4
```

Yayma ile üretilen nesne doğru veriyi taşır ama **zincirini kaybetmiştir**: prototipi
`Object.prototype` olur, `bicimle` bulunamaz, `instanceof` sonucu olumsuzdur ve nesne
donmuş değildir. Kursun ilk dersindeki cümle burada karşılığını bulur — kopyalama kendi
özellikleri taşır, zinciri taşımaz.

`degerleDegistir` yöntemi zinciri `Object.create(Object.getPrototypeOf(this))` ile
kurduğu için sonuç gerçek bir ölçüm kaydıdır. Yapıcı yerine mevcut prototipin
kullanılması ayrıca bir kazanç sağlar: alt sınıflardan çağrıldığında alt sınıfın
prototipi korunur.

Son satır kalıbın amacını doğrular: ilk kayıt değişmemiştir. Değişiklik istendiğinde eski
nesne yerinde kalır, yenisi üretilir. Bu, Programlama Temelleri kursundaki Fonksiyonel
Programlamaya Giriş dersinde tanıtılan değiştirilemezlik yaklaşımının nesne modelindeki
karşılığıdır.

## Özet

- `Object.freeze` kendi özellikleri yazılamaz ve yapılandırılamaz yapar, yeni özellik
  eklemeyi ve prototip değiştirmeyi yasaklar; geri alınamaz.
- Dondurma sığdır: iç nesneler ve prototip nesnesi etkilenmez, bu yüzden davranış hâlâ
  değiştirilebilir.
- Kapsamlar iç içedir — genişletmeyi engelleme, mühürleme, dondurma; ortadaki seçenek
  alan kümesini sabitler, değerleri serbest bırakır.
- Derin dondurma özyinelemeli bir gezintidir; çevrimlere karşı ziyaret işaretlemesi
  gerekir ve maliyeti nesne sayısıyla artar.
- Dondurulmuş nesnede güncelleme, yeni nesne üretmeye dönüşür; nesne yayma zinciri
  kaybettiği için prototip açıkça kurulmalıdır.

## Sonraki Adım

Bu konu boyunca yöntemler hep `this` üzerinden çalıştı: `bicimle` sensörü kayıttan,
erişimci ham değeri nesnenin kendisinden okudu. Ancak `this` değerinin ne olacağı
fonksiyonun nerede tanımlandığına değil, **nasıl çağrıldığına** bağlıdır — zincirden gelen
bir fonksiyon, hiç tanımadığı bir nesne üzerinde de çalışabilir. Sonraki konu bu bağlanma
kurallarını dört başlık altında ayırt edecek ve yöntemin nesnesinden koptuğu durumları
inceleyecek.
