---
title: 'Belge Nesne Modeli Kavramı'
source: 'https://academia.sh/tr/kurslar/web-temelleri-ve-html/belge-nesne-modeli-kavrami'
course: "Web'in Temelleri ve HTML"
language: tr
updated: '2026-08-17T18:09:32+00:00'
license: 'CC BY-SA 4.0'
---

# Belge Nesne Modeli Kavramı

Sözcük birimi akışının düğüm ağacına çevrilmesi, yığıtın işleyişi, düğüm türleri ve kaynak metinle ağaç arasındaki kopukluk.

Önceki ders ağaç kurma aşamasını bir cümleyle geçmişti: sözcük birimi akışı bir ağaca
çevrilir. Bu
ders o cümleyi açar. Ağaç, belgenin işlenmesinde bir ara ürün değil, **asıl üründür**:
biçem ona uygulanır, yerleşim onun üzerinden hesaplanır, betikler onu okur ve değiştirir.
Kaynak metin, ağaç kurulduktan sonra bir daha kullanılmaz.

Bu ağacın adı **Belge Nesne Modeli (Document Object Model)** — kısaca DOM'dur. Ad iki şeyi
birden söyler: belgenin bir **modeli**dir (kaynak metnin kendisi değil, ondan üretilmiş
yapılı bir gösterim) ve **nesnelerden** oluşur (her düğüm sorgulanabilir ve
değiştirilebilir bir birimdir).

## Neden Ağaç

Veri Yapıları kursundaki Ağaç Terminolojisi dersinde ağaç, her düğümün tek bir ebeveyni ve
sıralı çocukları olan yapı olarak tanımlanmıştı. İşaretlemenin ürettiği yapı tam olarak
budur, çünkü işaretlemenin kendisi iç içedir: bir öge ya bütünüyle başka bir ögenin içinde
yer alır ya da bütünüyle dışındadır. Kısmi örtüşme —bir ögenin yarısının içeride, yarısının
dışarıda kalması— tanımlı değildir.

Bu kısıt, iç içeliği yığıtla izlemeyi olanaklı kılar. Veri Yapıları kursundaki Yığıtlar
dersinde son giren ilk çıkar davranışı tanımlanmıştı; ağaç kurucu tam olarak bunu kullanır:
açılan öge yığıta konur, kapanan öge yığıttan alınır, yeni düğüm her zaman yığıtın
tepesindeki ögenin çocuğu olur.

## Kurucu Algoritma

Aşağıdaki betik, sözcük birimi akışından ağaç kuran algoritmanın çekirdeğini
gerçekleştirir. Önceki dersteki çözümleyiciye iki kural eklenmiştir: boş ögeler yığıta
girmez, bazı ögeler başka bir öge açıldığında kendiliğinden kapanır.

```js
// agac.mjs — birim akisindan dugum agaci kurar
const BOS_ETIKET = new Set(["br", "hr", "img", "input", "link", "meta"]);
const KAPATAN = { li: ["li"], p: ["p"], h1: ["p"], div: ["p"], ul: ["p"] };

function birimleriAyir(metin) {
  const birimler = [];
  let i = 0;
  while (i < metin.length) {
    const k = metin.indexOf("<", i);
    if (k === -1) { birimler.push({ tur: "metin", deger: metin.slice(i) }); break; }
    if (k > i) birimler.push({ tur: "metin", deger: metin.slice(i, k) });
    const son = metin.indexOf(">", k);
    const ic = metin.slice(k + 1, son);
    if (ic.startsWith("!")) birimler.push({ tur: "belge-turu", deger: ic.slice(1) });
    else if (ic.startsWith("/")) birimler.push({ tur: "kapanis", ad: ic.slice(1).toLowerCase() });
    else {
      const bosluk = ic.search(/[\s/]/);
      birimler.push({ tur: "acilis", ad: (bosluk === -1 ? ic : ic.slice(0, bosluk)).toLowerCase() });
    }
    i = son + 1;
  }
  return birimler;
}

function agacKur(metin) {
  const kok = { tur: "belge", ad: "#belge", cocuklar: [] };
  const yigit = [kok];
  const tepe = () => yigit[yigit.length - 1];
  for (const birim of birimleriAyir(metin)) {
    if (birim.tur === "metin") {
      if (birim.deger.trim() === "") continue;
      tepe().cocuklar.push({ tur: "metin", deger: birim.deger.trim(), cocuklar: [] });
    } else if (birim.tur === "acilis") {
      while (yigit.length > 1 && (KAPATAN[birim.ad] ?? []).includes(tepe().ad)) yigit.pop();
      const dugum = { tur: "eleman", ad: birim.ad, cocuklar: [] };
      tepe().cocuklar.push(dugum);
      if (!BOS_ETIKET.has(birim.ad)) yigit.push(dugum);
    } else if (birim.tur === "kapanis") {
      const yer = yigit.map((d) => d.ad).lastIndexOf(birim.ad);
      if (yer > 0) yigit.length = yer;
    }
  }
  return kok;
}

function yaz(dugum, derinlik = 0) {
  const girinti = "  ".repeat(derinlik);
  if (dugum.tur === "metin") console.log(`${girinti}"${dugum.deger}"`);
  else console.log(`${girinti}${dugum.ad}`);
  for (const cocuk of dugum.cocuklar) yaz(cocuk, derinlik + 1);
}

function say(dugum, sayac = { eleman: 0, metin: 0, derinlik: 0 }, derinlik = 0) {
  if (dugum.tur === "eleman") sayac.eleman += 1;
  if (dugum.tur === "metin") sayac.metin += 1;
  sayac.derinlik = Math.max(sayac.derinlik, derinlik);
  for (const cocuk of dugum.cocuklar) say(cocuk, sayac, derinlik + 1);
  return sayac;
}

const belge = `<!doctype html>
<html>
<head><title>Kuzey Yamac Istasyonu</title></head>
<body>
<h1>Kuzey Yamac Istasyonu</h1>
<p>Deniz seviyesinden 1840 metre yukseklikte.
<ul>
<li>Sicaklik
<li>Bagil nem
</ul>
</body>
</html>`;

const agac = agacKur(belge);
yaz(agac);
console.log("---");
console.log(say(agac));
```

```
#belge
  html
    head
      title
        "Kuzey Yamac Istasyonu"
    body
      h1
        "Kuzey Yamac Istasyonu"
      p
        "Deniz seviyesinden 1840 metre yukseklikte."
      ul
        li
          "Sicaklik"
        li
          "Bagil nem"
---
{ eleman: 9, metin: 5, derinlik: 5 }
```

Kaynak metinde `p` ögesinin kapanış etiketi yoktur ve iki `li` ögesinin de yoktur. Ağaçta
buna karşın üçü de kapanmış, doğru yerlerde durmaktadır. Bunu sağlayan `KAPATAN`
tablosudur: `ul` açıldığında açık `p` kapanır, `li` açıldığında açık `li` kapanır. Bu
kurallar isteğe bağlı bir kolaylık değil, dilin tanımının parçasıdır; her ayrıştırıcı
aynılarını uygular.

## Düğüm Türleri

Çıktıda üç tür düğüm görünür ve dördüncüsü belgenin kökünde durur.

**Belge düğümü**, ağacın köküdür. Bir ögeye karşılık gelmez; ağacın tamamının tutamağıdır.

**Öge düğümleri**, açılış etiketlerinden üretilir. Adı, öznitelikleri ve sıralı çocukları
vardır.

**Metin düğümleri**, etiketler arasındaki karakterlerden üretilir. Çocukları yoktur;
ağacın yaprağıdır. Yukarıdaki sayımdaki beş metin düğümü, belgedeki beş metin parçasına
karşılık gelir.

**Yorum düğümleri** (`<!-- ... -->` yazımı), belgede durur ve çizilmez. Betikler bunları
okuyabilir; işaretlemeye gömülmüş bilgiyi gizli saymamak gerekir.

Sayımda `eleman: 9` değeri, kaynak metindeki dokuz açılış etiketine karşılık gelir.
`derinlik: 5`, kökten en uzak yaprağa kadar geçilen kenar sayısıdır: belge → `html` →
`body` → `ul` → `li` → metin düğümü.

## Kaynak Metinde Bulunmayan Ögeler

Yukarıdaki örnekte `html`, `head` ve `body` ögeleri kaynak metinde yazılıydı. Yazılmasalardı
da ağaçta olurlardı. Bu, önceki derste kurulan etiket–öge ayrımının en somut sonucudur:
**ağaçtaki her ögenin kaynak metinde bir etiketi yoktur.**

Ters yönlü bir sonuç da vardır: kaynak metindeki her etiket ağaçta bir ögeye karşılık
gelmez. Eşleşen açılışı olmayan bir kapanış etiketi yok sayılır; yukarıdaki algoritmada
`lastIndexOf` çağrısı `-1` döndürdüğünde hiçbir şey yapılmaması bunun karşılığıdır.

Bu iki yönlü kopukluk, bir belgeyi doğrulamanın neden kaynak metne bakarak yapılamayacağını
açıklar. Sorulması gereken soru "ne yazdım" değil, "ne kuruldu"dur.

## Boş Ögeler

Bazı ögelerin içeriği olamaz ve bu nedenle kapanış etiketleri yoktur: `br`, `hr`, `img`,
`input`, `link`, `meta` ve birkaçı daha. Bunlara **boş öge (void element)** denir.
Algoritmada bu ögeler yığıta hiç konmaz; ağaca çocuk olarak eklenir ve yığıtın tepesi
değişmez.

Boş ögeler için `<br/>` biçiminde kapatma yazımı ayrıştırıcı tarafından kabul edilir ancak
bir etkisi yoktur; öge zaten boştur. Boş olmayan bir öge için aynı yazım —örneğin
`<div/>`— beklenen etkiyi yapmaz: öge kapanmaz, içerik onun içine akmayı sürdürür.

## Ağaç Yaşayan Bir Yapıdır

Ağaç kurulduktan sonra donmaz. Betikler düğüm ekleyebilir, çıkarabilir, özniteliklerini
değiştirebilir; her değişiklik biçem ve yerleşim aşamalarının ilgili bölümünü yeniden
çalıştırır. Bu nedenle bir sayfanın belirli bir andaki ağacı ile sunucudan gelen kaynak
metin birbirinden ayrılabilir: kaynak metin ilk durumu, ağaç o andaki durumu anlatır.

Bu kursta betik yazılmayacak; ancak yazılan işaretlemenin doğrudan bir veri yapısına
çevrildiğini bilmek, sonraki kursların dayanağıdır. İşaretleme yazmak, bir metin dizmek
değil, bir ağaç bildirmektir.

## Özet

- Belge Nesne Modeli, sözcük birimi akışından kurulan düğüm ağacıdır; biçem, yerleşim ve
  betikler kaynak metne değil bu ağaca uygulanır.
- Ağaç kurucu yığıt kullanır: açılan öge yığıta girer, kapanan öge çıkar, yeni düğüm
  yığıtın tepesindeki ögenin çocuğu olur.
- Kapanış etiketi yazılmayan bazı ögeler, başka bir öge açıldığında kendiliğinden kapanır;
  bu kurallar dilin tanımının parçasıdır.
- Dört düğüm türü vardır: belge, öge, metin ve yorum. Yorum düğümleri çizilmez ama belgede
  durur.
- Kaynak metinle ağaç bire bir örtüşmez: yazılmayan ögeler ağaçta belirebilir, yazılan
  bazı etiketler ağaca hiç geçmeyebilir.
- Boş ögelerin içeriği olamaz ve yığıta girmezler; kapatma yazımı onlarda etkisiz, boş
  olmayan ögelerde yanıltıcıdır.

## Sonraki Adım

Bu ders ağacın belge metninden nasıl kurulduğunu gösterdi ve ayrıştırmanın kesintisiz
ilerlediğini varsaydı. Gerçekte belge, kendisinden başka kaynaklara başvurur: biçem
dosyaları, betikler, görseller. Bu başvurular ayrıştırma sürerken ortaya çıkar ve bir
bölümü ayrıştırmayı durdurur. Sonraki ders, hangi kaynağın hangi aşamayı beklettiğini ve
bunun belgede nereye yazıldığıyla nasıl değiştiğini bir olay çizelgesi üzerinden inceler.
