---
title: Prototip
source: 'https://academia.sh/tr/kurslar/tasarim-kaliplari/prototip'
course: 'Tasarım Kalıpları'
language: tr
updated: '2026-08-17T18:10:38+00:00'
license: 'CC BY-SA 4.0'
---

# Prototip

Nesneyi kurmak yerine var olan bir nesneyi kopyalayarak yaratma: türetilmiş tarifelerin alanlarını elle yazan sürüm ile prototipi klonlayan sürümün karşılaştırılması, prototipe yeni bir alan eklendiğinde eksik alan sayısının ölçülmesi, sığ kopyanın paylaştığı alt nesne sayısının sayılması ve türetme zincirinin sessiz değişiklik olarak geri dönen bedeli.

Kurucu her nesneyi sıfırdan kurar. Kitaplıkta kurulacak nesnelerin çoğu ise birbirinin küçük
bir sapmasıdır: sözleşmeli müşteri tarifesi standart tarifenin iki alanı değişmiş hâli, bölgesel
tarife bir bölge katsayısı değişmiş hâli, kurumsal tarife de sözleşmeli tarifenin bir alanı
değişmiş hâli. Bu nesneleri adım adım kurmak, aynı alanları defalarca yazmak demektir.

**Prototip** (prototype) kalıbı yaratımı kurulumdan kopyalamaya çevirir: yeni nesne, var olan
bir nesnenin kopyası alınıp üzerinde birkaç alan değiştirilerek elde edilir. Bu dersin iki
ölçüsü var. Birincisi kazanç: prototipe yeni bir alan eklendiğinde türetilmiş nesnelerde kaç
alan eksik kalıyor. İkincisi bedel: aynı bağın istenmeyen bir değişikliği kaç nesneye taşıdığı
ve kopyanın kaç alt nesneyi prototiple paylaştığı.

## Elle Yazılan Türetilmiş Tarifeler

Birinci sürümde dört tarife de bağımsızdır. Her biri beş alanını kendi metninde taşır.

```js
// elle/tarife.mjs — her turetilmis tarife butun alanlarini yeniden yazar
export const standart = {
  ad: "standart",
  kademeler: [[1, 3900], [5, 6400], [20, 11800]],
  bolge: { "34": 100, "06": 115, "65": 140 },
  asgariUcret: 3900,
  sigortaOrani: 0.004,
};

export const sozlesmeli = {
  ad: "sozlesmeli",
  kademeler: [[1, 3900], [5, 6400], [20, 11800]],
  bolge: { "34": 100, "06": 115, "65": 140 },
  asgariUcret: 3200,
  sigortaOrani: 0.003,
};

export const bolgesel = {
  ad: "bolgesel",
  kademeler: [[1, 3900], [5, 6400], [20, 11800]],
  bolge: { "34": 100, "06": 115, "65": 125 },
  asgariUcret: 3900,
  sigortaOrani: 0.004,
};

export const kurumsal = {
  ad: "kurumsal",
  kademeler: [[1, 3900], [5, 6400], [20, 11800]],
  bolge: { "34": 100, "06": 115, "65": 140 },
  asgariUcret: 3200,
  sigortaOrani: 0.002,
};
```

Kademe tablosu dört kez, bölge tablosu üç kez aynı biçimde yazılmıştır. Bu, Temiz Kod kursunda
tanımlanan bilgi yinelemesidir: dört nesnenin kademe tablosunun eşit kalması hiçbir düzenekle
güvence altında değildir.

## Prototipten Klonlama

İkinci sürümde yalnız standart tarife tam yazılır. Diğerleri `tureti` çağrısıyla elde edilir:
prototip klonlanır, ada ve türetildiği prototipin adına yazılır, sonra istenen alanlar üzerine
geçirilir.

```js
// prototip/tarife.mjs — turetilmis tarifeler prototipi klonlayip alan degistirir
export const standart = {
  ad: "standart",
  kademeler: [[1, 3900], [5, 6400], [20, 11800]],
  bolge: { "34": 100, "06": 115, "65": 140 },
  asgariUcret: 3900,
  sigortaOrani: 0.004,
};

export function tureti(prototip, ad, degisiklik) {
  const kopya = structuredClone(prototip);
  return Object.assign(kopya, { ad, tureten: prototip.ad }, degisiklik);
}

export const sozlesmeli = tureti(standart, "sozlesmeli", { asgariUcret: 3200, sigortaOrani: 0.003 });
export const bolgesel = tureti(standart, "bolgesel", { bolge: { ...standart.bolge, "65": 125 } });
export const kurumsal = tureti(sozlesmeli, "kurumsal", { sigortaOrani: 0.002 });
```

Son satır kalıbın ayırt edici yanını gösteriyor: kurumsal tarife standart tarifeden değil,
**sözleşmeli tarifeden** türer. Prototip bir sınıf değil, çalışan bir nesnedir; dolayısıyla
türetilmiş bir nesne de kendisi prototip olabilir. Bu düzeneğin JavaScript'in kendi nesne
modelindeki `[[Prototype]]` bağıyla ilgisi yoktur; JavaScript Nesne Modeli kursunda ele alınan
o bağ arama zinciri kurar, buradaki klon ise bağımsız bir nesnedir ve alanlarını kopya olarak
taşır.

Aşağıdaki betik verilen dizindeki dört tarifeyle aynı gönderinin ücretini hesaplar. İki
sürümün eşdeğerliği bununla sınanır.

```js
// fiyat.mjs — verilen dizindeki dort tarifeyle ayni gonderinin ucreti
const dizin = process.argv[2];
const t = await import(`./${dizin}/tarife.mjs`);
const G = { agirlik: 2.4, il: "65", deger: 180000 };

const ucret = (tf) => {
  const taban = tf.kademeler.find(([ust]) => G.agirlik <= ust)?.[1] ?? 15000;
  const ham = Math.round((taban * (tf.bolge[G.il] ?? 160)) / 100) +
    Math.round(G.deger * tf.sigortaOrani);
  return Math.max(ham, tf.asgariUcret);
};

for (const ad of ["standart", "sozlesmeli", "bolgesel", "kurumsal"])
  console.log(`${dizin.padEnd(9)} ${ad.padEnd(11)} ${ucret(t[ad])} kurus`);
```

```sh
node fiyat.mjs elle
node fiyat.mjs prototip
```

```
elle      standart    9680 kurus
elle      sozlesmeli  9500 kurus
elle      bolgesel    8720 kurus
elle      kurumsal    9320 kurus
prototip  standart    9680 kurus
prototip  sozlesmeli  9500 kurus
prototip  bolgesel    8720 kurus
prototip  kurumsal    9320 kurus
```

Dört ücret de aynı. Fark yalnız türetilmiş nesnelerin nasıl elde edildiğinde.

## Sığ Kopya ile Derin Kopya

Kalıbın ilk tuzağı kopyanın derinliğidir. Nesne yayma (`{ ...prototip }`) alanları birer birer
kopyalar, ama alan bir nesneye ya da diziye başvuruyorsa kopyalanan şey başvurunun kendisidir.
Aşağıdaki ölçer prototipin iki alt nesnesi için başvuru eşitliğini sayar, sonra her iki kopyada
bir kademe değerini değiştirip prototipe ne olduğunu yazar.

```js
// paylasim.mjs — sig ve derin kopyanin prototiple paylastigi alt nesne sayisi
import { standart } from "./prototip/tarife.mjs";

const ALT = ["kademeler", "bolge"];
const paylasilan = (k) => ALT.filter((a) => k[a] === standart[a]).length;

const sig = { ...standart, ad: "sig-kopya" };
const derin = structuredClone(standart);
derin.ad = "derin-kopya";

console.log(`sig   paylasilan-alt-nesne=${paylasilan(sig)}`);
console.log(`derin paylasilan-alt-nesne=${paylasilan(derin)}`);

derin.kademeler[0][1] = 4200;
console.log(`derin kademesi degisti -> standart ilk kademe=${standart.kademeler[0][1]}`);
sig.kademeler[0][1] = 4200;
console.log(`sig   kademesi degisti -> standart ilk kademe=${standart.kademeler[0][1]}`);
```

```sh
node paylasim.mjs
```

```
sig   paylasilan-alt-nesne=2
derin paylasilan-alt-nesne=0
derin kademesi degisti -> standart ilk kademe=3900
sig   kademesi degisti -> standart ilk kademe=4200
```

Sığ kopya iki alt nesneyi prototiple paylaşıyor. Sonucu son satırda: sığ kopyanın kademesine
yazmak prototipin kademesini de değiştirdi. Bu, Bağlaşım Türleri dersinde ölçülen ortak
bağlaşımın aynısıdır — iki nesnenin davranışı ortak değiştirilebilir bir duruma bağlıdır — ve
kalıbın yanlış uygulandığı en yaygın biçimdir. Derin kopyada paylaşılan alt nesne sayısı sıfır
olduğu için prototip değişmedi.

## Prototipe Eklenen Alanın İzlenmesi

Kalıbın kazancı prototip değiştiğinde ortaya çıkar. Aşağıdaki ölçer türetilmiş üç tarifede
tanımsız kalan alanları sayar, sigorta oranlarını listeler ve türetme zincirinin derinliğini
verir.

```js
// alan-say.mjs — turetilmis tarifelerde eksik alan, sigorta orani ve prototip zinciri
const dizin = process.argv[2];
const t = await import(`./${dizin}/tarife.mjs`);
const ALAN = ["ad", "kademeler", "bolge", "asgariUcret", "sigortaOrani", "yakitEki"];
const TURETILMIS = ["sozlesmeli", "bolgesel", "kurumsal"];

const eksik = TURETILMIS.reduce(
  (toplam, ad) => toplam + ALAN.filter((a) => t[ad][a] === undefined).length, 0);
const oran = TURETILMIS.map((ad) => t[ad].sigortaOrani).join(",");
const zincir = (ad) => (t[ad].tureten === undefined ? 0 : 1 + zincir(t[ad].tureten));
const derinlik = Math.max(...TURETILMIS.map(zincir));

console.log(`${dizin.padEnd(13)} eksik-alan=${eksik} sigorta-orani=${oran} ` +
  `zincir-derinligi=${derinlik}`);
```

Değişiklik tek bir istektir: standart tarifeye yakıt eki alanı eklenir ve sigorta oranı
yükseltilir. Aşağıdaki betik bu düzenlemeyi iki ağacın kopyalarına birebir aynı biçimde
uygular; yalnız standart tarifenin alanına dokunduğundan emin olmak için metni ad üzerinden
konumlar.

```js
// yama.mjs — standart tarifenin sigorta oranini yukseltir ve yakit eki alani ekler
import { readFileSync, writeFileSync } from "node:fs";

const yol = process.argv[2];
const metin = readFileSync(yol, "utf8");
const bas = metin.indexOf('ad: "standart"');
const alan = metin.indexOf("sigortaOrani:", bas);
const satirSonu = metin.indexOf("\n", alan);
writeFileSync(yol,
  `${metin.slice(0, alan)}sigortaOrani: 0.006,\n  yakitEki: 250,${metin.slice(satirSonu)}`);
```

```sh
node alan-say.mjs elle
node alan-say.mjs prototip
cp -r elle elle-yeni
cp -r prototip prototip-yeni
node yama.mjs elle-yeni/tarife.mjs
node yama.mjs prototip-yeni/tarife.mjs
node alan-say.mjs elle-yeni
node alan-say.mjs prototip-yeni
node fiyat.mjs elle-yeni
node fiyat.mjs prototip-yeni
```

```
elle          eksik-alan=3 sigorta-orani=0.003,0.004,0.002 zincir-derinligi=0
prototip      eksik-alan=3 sigorta-orani=0.003,0.004,0.002 zincir-derinligi=2
elle-yeni     eksik-alan=3 sigorta-orani=0.003,0.004,0.002 zincir-derinligi=0
prototip-yeni eksik-alan=0 sigorta-orani=0.003,0.006,0.002 zincir-derinligi=2
elle-yeni standart    10040 kurus
elle-yeni sozlesmeli  9500 kurus
elle-yeni bolgesel    8720 kurus
elle-yeni kurumsal    9320 kurus
prototip-yeni standart    10040 kurus
prototip-yeni sozlesmeli  9500 kurus
prototip-yeni bolgesel    9080 kurus
prototip-yeni kurumsal    9320 kurus
```

Kazanç ilk sütunda. Değişiklikten önce iki sürümde de üç alan eksikti; yakıt eki hiçbir
tarifede yoktu. Düzenlemeden sonra elle yazılan sürümde eksik alan sayısı 3'te kaldı: yeni alan
yalnız standart tarifeye girdi, türetilmiş üç tarife onu hiç görmedi. Klonlayan sürümde sayı
0'a indi, çünkü türetilmiş tarifeler yükleme anında prototipten üretilir.

Bedel ikinci ve üçüncü sütunda. Sigorta oranı sözleşmeli ve kurumsal tarifelerde üzerine
yazıldığı için değişmedi; bölgesel tarifede yazılmamıştı ve 0.004'ten 0.006'ya çıktı. Ücret
satırlarında karşılığı görünüyor: bölgesel tarifenin ücreti elle yazılan sürümde 8720 kuruşta
kaldı, klonlayan sürümde 9080 kuruşa çıktı. Bu değişiklik hiçbir yerde istenmemiştir; yalnız
prototipe dokunulmuştur.

Üçüncü sütun bu bedelin neden zor fark edildiğini söylüyor. Türetme zinciri derinliği 2'dir:
kurumsal tarife sözleşmeli tarifeden, o da standart tarifeden türer. Bir alanın nihai değerini
bulmak için zinciri geriye doğru izlemek ve her basamakta alanın üzerine yazılıp yazılmadığına
bakmak gerekir. Elle yazılan sürümde bu derinlik 0'dır: her tarifenin bütün alanları kendi
metnindedir.

İki sayının aynı düzeneğin iki yüzü olduğuna dikkat edilmelidir. Yeni alanın kendiliğinden
taşınması ile istenmeyen değişikliğin kendiliğinden taşınması aynı bağdır. Kalıp bu yüzden
türetilmiş nesnelerin gerçekten prototiple birlikte değişmesi gerektiği durumlarda uygulanır;
bağımsız değişmesi gereken nesneler için taşınan değişiklik kazanç değil kusurdur.

## Özet

- Prototip kalıbı yeni nesneyi kurulum adımlarıyla değil, var olan bir nesnenin kopyası
  üzerinden üretir; prototip bir sınıf değil çalışan bir nesnedir, dolayısıyla türetilmiş bir
  nesne de prototip olabilir.
- Prototipe yeni bir alan eklendiğinde elle yazılan sürümde eksik alan sayısı 3'te kaldı,
  klonlayan sürümde 0'a indi.
- Aynı düzenleme bölgesel tarifenin sigorta oranını 0.004'ten 0.006'ya taşıdı ve ücretini 8720
  kuruştan 9080 kuruşa çıkardı; bu değişiklik istenmemişti.
- Sığ kopya prototiple 2 alt nesne paylaştı ve kopyanın kademesine yazmak prototipin kademesini
  de değiştirdi; derin kopyada paylaşılan alt nesne sayısı 0'dır.
- Türetme zinciri derinliği klonlayan sürümde 2, elle yazılan sürümde 0'dır; bir alanın nihai
  değeri ancak zincir izlenerek bulunur.

## Sonraki Adım

Dört yaratımsal düzenek de nesnenin nereden geldiğini düzenledi, ama hepsinde nesne çağıran
tarafından elde tutuldu. Bir sonraki soru nesnenin **kaç tane** olduğudur. Kitaplıkta tarife
kaydı gibi tek bir örneğinin bulunması istenen nesneler var; bu isteği karşılamanın en kısa
yolu nesneyi modül düzeyinde kurup her yerden aynı örneğe erişmektir. Sonraki ders bunun
sınanabilirlik cinsinden bedelini ölçer: aynı sınama kümesi tekil örnek üzerinden
koşturulduğunda kaç sınamanın başarısız olduğunu, sıra değiştiğinde sonucun değişip
değişmediğini ve durumu sıfırlayan düzeneğin dışa açılan yüzeye kaç ad eklediğini sayar.
