---
title: 'Şablon ve İfade Sözdizimi'
source: 'https://academia.sh/tr/kurslar/bilesen-tabanli-gelistirme/sablon-ve-ifade-sozdizimi'
course: 'Bileşen Tabanlı Arayüz Geliştirme'
language: tr
updated: '2026-08-17T18:09:13+00:00'
license: 'CC BY-SA 4.0'
---

# Şablon ve İfade Sözdizimi

İşaretlemenin veriye bağlanması; şablonun bir kez derlenip çok kez çalıştırılması, sabit ve devingen parçaların ayrılması, ifadelerin kapsamı ile sınırı, metin kaçırma ve öznitelik–özellik bağlaması ayrımı.

Önceki dersin bileşenleri görünüm tanımını iç içe işlev çağrılarıyla kurdu. Bir ölçüm
tablosunun bütün yapısı bu biçimde yazıldığında işaretlemenin şekli kaybolur: hangi ögenin
nerede kapandığı, hangi özniteliğin hangi ögeye ait olduğu çağrı parantezleri arasında
okunur hâle gelmez.

Bu ders işaretlemenin kendi söz diziminde yazılıp veriye bağlanmasını ele alır. Kurulacak
mekanizmanın adı **şablon (template)** dur: içinde ifade taşıyan bir işaretleme metni ve
onu görünüm tanımı üreten bir işleve çeviren bir derleme adımı.

## İki Yazım Ailesi

İşaretlemeyi programa sokmanın iki yolu vardır ve çerçeve aileleri bu ayrımla bölünür.

Birinci yolda **işaretleme dilin içine gömülür**: programlama dilinin söz dizimi
genişletilir, işaretleme dilin bir ifadesi hâline gelir. İfade yeri diye ayrı bir kavram
yoktur; işaretlemenin içindeki her şey zaten dilin ifadesidir. Kazanç, dilin bütün
olanaklarının doğrudan kullanılabilmesidir.

İkinci yolda **şablon ayrı bir metindir**: işaretlemeye özel imler eklenir ve bu metin
derlenerek işleve çevrilir. Şablon dili dilden küçüktür; yalnızca ifadelere ve birkaç
yönergeye izin verir. Kazanç, küçük dilin çözümlenebilir olmasıdır: derleyici hangi
parçanın sabit hangisinin devingen olduğunu bilir ve bu bilgiyle iş yapabilir.

İki yol da aynı yere varır: durumdan görünüm tanımı üreten bir işlev. Fark, bu işlevin ne
zaman ve ne kadar bilgiyle üretildiğidir.

## Şablonun Derlenmesi

Aşağıdaki derleyici ikinci yolun küçük bir örneğidir. Şablon bir kez çözümlenir, sonuç bir
komut ağacına dönüşür; her oluşturmada yalnızca bu ağaç çalıştırılır.

```js
// sablon-derleyici.mjs — sablon metnini gorunum ureten bir isleve derler
const SABLON = `
<div class="rozet" :durum="deger >= esik ? 'asim' : 'normal'" @tikla="ac">
  <span class="ad">{{ad}}</span>
  <span class="deger">{{deger}} {{birim}}</span>
</div>`.trim();

// 1) Sozcuksel cozumleme: etiketler ve metin parcalari.
// Etiket eslemesi tirnak icindeki ">" karakterini atlar.
const ETIKET = /<\/[a-z][\w-]*>|<[a-z][\w-]*(?:\s+[:@]?[\w-]+(?:="[^"]*")?)*\s*>|[^<]+/g;
const parcala = (metin) => metin.match(ETIKET) ?? [];

// 2) Metni sabit dilim ve ifade olarak ayirir: "{{ad}}: {{deger}}" → 4 parca.
function metniAyir(metin) {
  const parcalar = [];
  let son = 0;
  for (const eslesme of metin.matchAll(/\{\{([^}]+)\}\}/g)) {
    if (eslesme.index > son)
      parcalar.push({ tur: "sabit", deger: metin.slice(son, eslesme.index) });
    parcalar.push({ tur: "ifade", kaynak: eslesme[1].trim() });
    son = eslesme.index + eslesme[0].length;
  }
  if (son < metin.length) parcalar.push({ tur: "sabit", deger: metin.slice(son) });
  return parcalar;
}

// 3) Oznitelikleri uce ayirir: sabit, bagli (:) ve olay (@).
function oznitelikleriAyir(govde) {
  const sabit = {}, bagli = {}, olay = {};
  for (const [, ad, deger] of govde.matchAll(/([:@]?[\w-]+)="([^"]*)"/g)) {
    if (ad.startsWith(":")) bagli[ad.slice(1)] = deger;
    else if (ad.startsWith("@")) olay[ad.slice(1)] = deger;
    else sabit[ad] = deger;
  }
  return { sabit, bagli, olay };
}

// 4) Derleme: sablon bir kez cozumlenir, sonuc bir komut agacina donusur.
function derle(sablon, kapsamAdlari) {
  const degerlendir = (kaynak) =>
    new Function(...kapsamAdlari, `return (${kaynak});`);
  const yigit = [{ cocuklar: [] }];
  let sabitSayisi = 0, devingenSayisi = 0;

  for (const parca of parcala(sablon)) {
    if (parca.startsWith("</")) { yigit.pop(); continue; }
    if (parca.startsWith("<")) {
      const ad = parca.match(/^<([a-z]+)/)[1];
      const { sabit, bagli, olay } = oznitelikleriAyir(parca);
      sabitSayisi += Object.keys(sabit).length;
      devingenSayisi += Object.keys(bagli).length + Object.keys(olay).length;
      const dugum = {
        ad, sabit, cocuklar: [],
        bagli: Object.fromEntries(Object.entries(bagli)
          .map(([k, v]) => [k, degerlendir(v)])),
        olay: Object.fromEntries(Object.entries(olay)
          .map(([k, v]) => [k, degerlendir(v)])),
      };
      yigit.at(-1).cocuklar.push(dugum);
      yigit.push(dugum);
      continue;
    }
    if (!parca.trim()) continue;
    for (const p of metniAyir(parca.trim())) {
      if (p.tur === "sabit") { sabitSayisi++; yigit.at(-1).cocuklar.push(p.deger); }
      else { devingenSayisi++; yigit.at(-1).cocuklar.push(degerlendir(p.kaynak)); }
    }
  }
  console.log(`derleme: ${sabitSayisi} sabit parca, ${devingenSayisi} devingen parca`);
  return { kok: yigit[0].cocuklar[0], kapsamAdlari };
}

// 5) Calistirma: komut agaci + kapsam → gorunum tanimi.
function uret({ kok, kapsamAdlari }, kapsam) {
  const argumanlar = kapsamAdlari.map((ad) => kapsam[ad]);
  const cik = (d) => {
    if (typeof d === "string") return d;
    if (typeof d === "function") return String(d(...argumanlar));
    return {
      ad: d.ad,
      ozn: { ...d.sabit,
        ...Object.fromEntries(Object.entries(d.bagli)
          .map(([k, f]) => [k, f(...argumanlar)])),
        ...Object.fromEntries(Object.entries(d.olay)
          .map(([k, f]) => [`on:${k}`, f(...argumanlar).name || "islev"])) },
      cocuklar: d.cocuklar.map(cik),
    };
  };
  return cik(kok);
}

const KAPSAM = ["ad", "deger", "birim", "esik", "ac"];
const derlenmis = derle(SABLON, KAPSAM);

const yaz = (d, girinti = 0) => typeof d === "string"
  ? `${" ".repeat(girinti)}${JSON.stringify(d)}`
  : [`${" ".repeat(girinti)}<${d.ad}${Object.entries(d.ozn)
      .map(([k, v]) => ` ${k}=${JSON.stringify(v)}`).join("")}>`,
     ...d.cocuklar.map((c) => yaz(c, girinti + 2))].join("\n");

for (const olcum of [
  { ad: "Sıcaklık", deger: -4.2, birim: "°C", esik: 30, ac: () => {} },
  { ad: "Bağıl nem", deger: 94, birim: "%", esik: 90, ac: () => {} },
]) console.log(`\n${yaz(uret(derlenmis, olcum))}`);

// Ifade yalnizca bildirilen kapsam adlarini gorur.
try {
  new Function(...KAPSAM, "return (esikAsimSayisi);")("x", 0, "", 0, null);
} catch (hata) {
  console.log(`\nkapsamda olmayan ad: ${hata.constructor.name} — ${hata.message}`);
}
```

```
derleme: 4 sabit parca, 5 devingen parca

<div class="rozet" durum="normal" on:tikla="ac">
  <span class="ad">
    "Sıcaklık"
  <span class="deger">
    "-4.2"
    " "
    "°C"

<div class="rozet" durum="asim" on:tikla="ac">
  <span class="ad">
    "Bağıl nem"
  <span class="deger">
    "94"
    " "
    "%"

kapsamda olmayan ad: ReferenceError — esikAsimSayisi is not defined
```

Çıktının dört sonucu vardır.

**Derleme bir kez, çalıştırma çok kez.** Çözümleme satırı yalnızca bir kez yazılmıştır;
iki farklı ölçüm için görünüm üretilirken şablon metnine bir daha bakılmamıştır. On beş
rozet için de aynıdır. Şablonun ayrıştırılması, oluşturma maliyetinin parçası değildir.

**Sabit ve devingen parçalar ayrılmıştır.** Derleyici dört parçanın hiçbir duruma bağlı
olmadığını bilir. Bu bilgi bir sonraki derste maliyet düşürmek için kullanılır:
karşılaştırılması gerekmeyen parçalar baştan bellidir.

**İfade, bildirilen kapsamda değerlendirilir.** Şablondaki `deger` adı, bileşenin
kapsamındaki `deger` değişkenidir; kapsamda bulunmayan bir ad çalışma zamanında hata
üretir. Şablonun gördüğü adlar bileşenin verdiği adlarla sınırlıdır.

**Üç bağlama türü ayrı imlerle yazılmıştır.** Ön ekli olmayan öznitelik sabittir; iki nokta
ön eki değeri bir ifadeden alır; kuyruklu a ön eki bir olay bağlar. Ayrımın söz diziminde
görünür olması, derleyicinin her birine farklı davranmasını sağlar.

## İfadelerin Sınırı

Şablon ifadeleri, oluşturma sırasında ve her oluşturmada çalışır. Bundan iki kural çıkar.

**İfade yan etki üretmemelidir.** Önceki dersin saflık koşulu şablona da uygulanır: içinde
durum değiştiren, istek başlatan ya da sayaç artıran bir ifade, oluşturma sayısına bağlı
davranır.

**İfade ucuz olmalıdır.** Şablonun içinde bir listeyi sıralamak ya da süzmek, her
oluşturmada yeniden hesaplanır. Bu hesabın bir kez yapılıp sonucunun saklanması, kursun
türetilmiş değerler dersinin konusudur.

Şablon dilinin ifadeyle sınırlı tutulması bu kuralları söz dizimi düzeyinde de destekler:
deyim yazılamayan bir dilde döngü kurmak, atama yapmak ya da hata yakalamak olanaksızdır.
Bu iş bileşenin gövdesine ait olur.

## Metin, Öznitelik ve Olay Bağlaması

Üç bağlama türünün davranışı birbirinden ayrıdır ve karıştırıldıklarında iki tanıdık sorun
doğar.

```js
// baglama-turleri.mjs — metin kacirma ile oznitelik/ozellik baglamasinin farki
// 1) Metin yerlestirme kacirir; ham ekleme kacirmaz.
const kacir = (s) => String(s)
  .replace(/&/g, "&amp;").replace(/</g, "&lt;")
  .replace(/>/g, "&gt;").replace(/"/g, "&quot;");

const not = 'Sensör <b>şüpheli</b> okuma';            // forma girilmis serbest metin
console.log(`metin yerlestirme : <p>${kacir(not)}</p>`);
console.log(`ham ekleme        : <p>${not}</p>`);

const etiket = 'kar" veri-yetki="tam';                 // tirnak tasiyan deger
console.log(`\noznitelik (kacirilmis): <li tur="${kacir(etiket)}">`);
console.log(`oznitelik (kacirilmamis): <li tur="${etiket}">`);
const oznitelikSayisi = (s) => [...s.matchAll(/[\w-]+="/g)].length;
console.log(`uretilen oznitelik sayisi — kacirilmis: ` +
  `${oznitelikSayisi(`<li tur="${kacir(etiket)}">`)}, ` +
  `kacirilmamis: ${oznitelikSayisi(`<li tur="${etiket}">`)}`);

// 2) Oznitelik belgedeki dizgi, ozellik yasayan degerdir; kullanici yazinca ayrisirlar.
function alanKur() {
  const dugum = { ozn: {}, canliDeger: "", kullaniciDokundu: false };
  return {
    dugum,
    oznitelikYaz(deger) {
      dugum.ozn.deger = String(deger);
      if (!dugum.kullaniciDokundu) dugum.canliDeger = String(deger); // ilk deger
    },
    ozellikYaz(deger) { dugum.canliDeger = String(deger); },
    kullaniciYazar(metin) { dugum.kullaniciDokundu = true; dugum.canliDeger = metin; },
  };
}

for (const tur of ["oznitelik", "ozellik"]) {
  const alan = alanKur();
  const yaz = (v) => tur === "oznitelik" ? alan.oznitelikYaz(v) : alan.ozellikYaz(v);
  yaz("kar");                       // ilk cizim: durumdaki arama metni
  alan.kullaniciYazar("kar de");    // kullanici yaziyor
  yaz("kar derinliği");             // durum guncellendi, yeniden cizim
  console.log(`\n${tur} baglamasi → belgedeki deger: ` +
    `${JSON.stringify(alan.dugum.ozn.deger ?? null)}, ` +
    `alanda gorunen: ${JSON.stringify(alan.dugum.canliDeger)}`);
}
```

```
metin yerlestirme : <p>Sensör &lt;b&gt;şüpheli&lt;/b&gt; okuma</p>
ham ekleme        : <p>Sensör <b>şüpheli</b> okuma</p>

oznitelik (kacirilmis): <li tur="kar&quot; veri-yetki=&quot;tam">
oznitelik (kacirilmamis): <li tur="kar" veri-yetki="tam">
uretilen oznitelik sayisi — kacirilmis: 1, kacirilmamis: 2

oznitelik baglamasi → belgedeki deger: "kar derinliği", alanda gorunen: "kar de"

ozellik baglamasi → belgedeki deger: null, alanda gorunen: "kar derinliği"
```

**Metin yerleştirme kaçırır.** Kullanıcının girdiği metin metin olarak kalır; içindeki
işaretleme karakterleri Web'in Temelleri ve HTML kursundaki karakter başvurularına
çevrilir. Bu, şablon söz diziminin varsayılan davranışıdır ve seçilmiş bir güvenlik
kararıdır. Aynı şablon dilinin sunduğu **ham ekleme** yolu bu korumayı kapatır: değer
işaretleme olarak yorumlanır. Ham eklemenin girdisi hiçbir zaman kullanıcıdan gelmemelidir.

**Öznitelik bağlaması da kaçırır.** Kaçırılmamış bir değer tırnağı kapatıp yeni bir
öznitelik açar: örnekte tek öznitelik yerine iki öznitelik üretilmiştir. Şablon
derleyicisinin değeri koyduğu yeri bilmesi, doğru kaçırmayı seçebilmesinin nedenidir; aynı
değer metin içinde, öznitelik içinde ve adres değeri olarak farklı kurallarla kaçırılır.

**Öznitelik ile özellik aynı şey değildir.** DOM API'si dersinde kurulan ayrım şablonda bir
seçime dönüşür. Öznitelik yazmak belgedeki dizgiyi değiştirir; kullanıcı alana
dokunduktan sonra alanın yaşayan değerini artık izlemez. Çıktının son iki satırı bunu
gösterir: öznitelik yolu belgedeki değeri günceller ama alanda görünen metin kullanıcının
yazdığı hâlde kalır. Özellik yolu yaşayan değeri günceller.

Kural buradan çıkar: **görüntülenen değeri taşıyan bağlamalar özellik, belgedeki
üstveriyi taşıyanlar öznitelik olarak yazılır.** Mantıksal öznitelikler ayrı bir durumdur:
belgede varlık–yokluk taşırlar, program tarafında ise doğru–yanlış; bir mantıksal
özniteliği yanlış değerle yazmak onu kaldırmakla aynı şey değildir.

**Olay bağlaması bir işlev bağlar.** Şablondaki `@tikla="ac"` imi bir dizgi değil, kapsamda
bulunan bir işlev başvurusu üretir; çıktıda `on:tikla="ac"` olarak görünen şey odur.
Değerin dizgi olarak yorumlanması, işaretlemenin içine kod yazmak anlamına gelirdi.

## Özet

- Şablon, işaretlemenin kendi söz diziminde yazılıp veriye bağlanmasıdır; derleme adımı onu
  görünüm tanımı üreten bir işleve çevirir.
- İşaretleme ya dilin içine gömülür ya da ayrı bir metin olarak derlenir; ikinci yolda
  derleyici sabit ve devingen parçaları ayırt edebilir.
- Şablon bir kez çözümlenir, üretilen komut ağacı her oluşturmada çalıştırılır; ayrıştırma
  oluşturma maliyetinin parçası değildir.
- Şablon ifadeleri bileşenin kapsamında değerlendirilir, yan etki üretmemeli ve ucuz
  olmalıdır; deyim yazılamaması bu kuralı söz dizimi düzeyinde destekler.
- Metin yerleştirme ve öznitelik bağlaması varsayılan olarak kaçırır; ham ekleme kaçırmaz
  ve girdisi kullanıcıdan gelmemelidir.
- Görüntülenen değeri taşıyan bağlamalar özellik, belgedeki üstveriyi taşıyanlar öznitelik
  olarak yazılır; olay bağlaması dizgi değil işlev başvurusu bağlar.

## Sonraki Adım

Bu dersin şablonu tek bir rozeti betimledi ve yapısı her durumda aynı kaldı: aynı ögeler,
aynı sırada. Gerçek bir pano ise değişken yapılıdır — süzgeç hiçbir ölçümle eşleşmediğinde
tablo yerine bir boş durum iletisi görünür, ölçüm listesi büyüyüp küçülür, satırlar yeniden
sıralanır. Sonraki ders şablona koşul ve yineleme yönergelerini ekler ve asıl soruyu sorar:
liste değiştiğinde yeni tanımdaki hangi satırın ağaçtaki hangi düğüme karşılık geldiğini ne
belirler?
