---
title: "DOM API'si"
source: 'https://academia.sh/tr/kurslar/tarayici-platformu/dom-apisi'
course: 'Tarayıcı ve Web Platformu'
language: tr
updated: '2026-08-17T18:09:11+00:00'
license: 'CC BY-SA 4.0'
---

# DOM API'si

Belge ağacını okuyan ve değiştiren arayüz; düğüm ile öge ayrımı, canlı koleksiyon ve durağan liste farkı, öznitelik–özellik ikiliği ve toplu değişikliğin maliyeti.

Web'in Temelleri ve HTML kursu bir belge kurdu: Kuzey Yamaç Ölçüm İstasyonu sayfası,
bölümlenmiş bir yapı, ölçüm tablosu ve erişilebilir bir gönderim formu. CSS ile Görsel
Sunum kursu o belgeye biçem verdi. İki kurs boyunca sayfa **durağandı**: sunucudan geldiği
biçimiyle duruyor, kullanıcının yaptığı hiçbir şey onu değiştirmiyordu.

Bu kurs sayfaya davranış ekler. Davranışın ilk koşulu, belgeyi bir program içinden
okuyabilmek ve değiştirebilmektir. Belge Nesne Modeli Kavramı dersinde ağacın kaynak
metinden nasıl kurulduğu gösterilmişti; o derste kurulan yapı bu derste **arayüzü olan bir
veri yapısı** hâline gelir.

## Ağaç Bir Nesne Grafiğidir

Ayrıştırıcının ürettiği her düğüm, programın erişebildiği bir nesnedir. Nesneler
birbirine ebeveyn, çocuk ve kardeş bağlarıyla bağlıdır; bu bağlar üzerinden ağacın her
noktasına ulaşılabilir.

İlk tuzak bu bağların ne taşıdığında saklıdır. Bir ögenin çocukları arasında yalnızca
ögeler yoktur: etiketler arasındaki boşluklar da metin düğümü olarak ağaca girer. Bu
nedenle API iki ayrı gezinme yolu sunar — biri bütün düğümleri, diğeri yalnızca öge
düğümlerini verir.

```js
// dugumler.mjs — cocuk dugumler ile cocuk ogeler arasindaki fark
const metin = (deger) => ({ tur: "metin", deger, cocuklar: [] });
const oge = (ad, ozn = {}, ...icerik) => {
  const dugum = { tur: "oge", ad, ozn, cocuklar: [], ebeveyn: null };
  for (const parca of icerik) {
    const cocuk = typeof parca === "string" ? metin(parca) : parca;
    cocuk.ebeveyn = dugum;
    dugum.cocuklar.push(cocuk);
  }
  return dugum;
};

// K01'de yazilan olcum listesinin agactaki karsiligi:
// <ul id="olcumler">
//   <li class="olcum">Sicaklik</li>
//   <li class="olcum">Bagil nem</li>
// </ul>
const liste = oge("ul", { id: "olcumler" },
  "\n  ",
  oge("li", { class: "olcum" }, "Sıcaklık"),
  "\n  ",
  oge("li", { class: "olcum" }, "Bağıl nem"),
  "\n");

const cocukDugumler = (d) => d.cocuklar;
const cocukOgeler = (d) => d.cocuklar.filter((c) => c.tur === "oge");

console.log("cocuk dugum sayisi :", cocukDugumler(liste).length);
console.log("cocuk oge sayisi   :", cocukOgeler(liste).length);
console.log("ilk cocuk dugum    :", JSON.stringify(cocukDugumler(liste)[0].deger));
console.log("ilk cocuk oge      :", cocukOgeler(liste)[0].ad);
```

```
cocuk dugum sayisi : 5
cocuk oge sayisi   : 2
ilk cocuk dugum    : "\n  "
ilk cocuk oge      : li
```

İki `li` ögesi arasında üç metin düğümü vardır ve üçü de yalnızca satır sonu ile
girintiden oluşur. Tarayıcı API'sinde bu ayrım `childNodes` ile `children`,
`firstChild` ile `firstElementChild`, `nextSibling` ile `nextElementSibling`
çiftleriyle karşılanır. İlk sütundakiler bütün düğümleri, ikinci sütundakiler yalnızca
ögeleri görür.

Bir belgeyi ilk düğümden gezerek dolaşan kod, işaretlemedeki girintiyi değiştirmekle
bozulabilir. Bu, kırılganlığın kaynağıdır ve sonraki bölümde ele alınan seçici tabanlı
erişimin gerekçesidir.

## Düğüm Seçme

Ağacı elle dolaşmak yerine, aranan düğüm bir seçiciyle tarif edilir. CSS ile Görsel Sunum
kursundaki Seçiciler dersinde tanımlanan sözdizim burada aynen geçerlidir: biçem
kurallarının hangi ögelere uygulanacağını belirleyen dil, programın hangi ögelere
erişeceğini de belirler.

İki temel işlem vardır. Biri eşleşen **ilk** ögeyi döndürür, diğeri eşleşenlerin
**tamamını**. İkisi de bir kökten başlar: belgenin tamamında arama yapılabildiği gibi,
belirli bir ögenin alt ağacında da arama yapılabilir. Alt ağaçta arama, aynı seçicinin
sayfanın başka bir yerindeki eşleşmelerini dışarıda bırakır ve bu nedenle bileşen
sınırları içinde çalışan kodun tercih ettiği biçimdir.

Bir de kimliğe göre erişim vardır. Kimlik belge içinde benzersiz olduğu için bu erişim
ağacı taramadan doğrudan bir dizinden okunur; ancak benzersizlik varsayımına dayanır.
Aynı kimlik iki kez yazılmışsa ilki döndürülür ve hata verilmez.

## Canlı Koleksiyon ve Durağan Liste

Seçme işleminin döndürdüğü şey iki farklı türden olabilir ve aradaki fark, kodun ağaç
değiştikten sonra ne göreceğini belirler.

```js
// koleksiyon.mjs — canli koleksiyon ile duragan liste arasindaki fark
const oge = (ad, ozn = {}, ...icerik) => {
  const dugum = { tur: "oge", ad, ozn, cocuklar: [], ebeveyn: null };
  for (const parca of icerik) {
    const cocuk = typeof parca === "string" ? { tur: "metin", deger: parca, cocuklar: [] } : parca;
    cocuk.ebeveyn = dugum;
    dugum.cocuklar.push(cocuk);
  }
  return dugum;
};

// Agactaki tum ogeleri on siralamayla dolasir.
function* ogeler(kok) {
  if (kok.tur === "oge") yield kok;
  for (const cocuk of kok.cocuklar) yield* ogeler(cocuk);
}

const esler = (o, secici) => {
  if (secici.startsWith(".")) return (o.ozn.class ?? "").split(/\s+/).includes(secici.slice(1));
  if (secici.startsWith("#")) return o.ozn.id === secici.slice(1);
  return o.ad === secici;
};

// Duragan liste: cagrildigi andaki eslesmeleri diziye kopyalar.
const hepsiniSec = (kok, secici) => [...ogeler(kok)].filter((o) => esler(o, secici));

// Canli koleksiyon: her okumada agaci yeniden tarar.
const canliKoleksiyon = (kok, secici) => ({
  get uzunluk() { return hepsiniSec(kok, secici).length; },
});

const liste = oge("ul", { id: "olcumler" },
  oge("li", { class: "olcum" }, "Sıcaklık"),
  oge("li", { class: "olcum" }, "Bağıl nem"));

const duragan = hepsiniSec(liste, "li");
const canli = canliKoleksiyon(liste, "li");
console.log("ekleme oncesi  — duragan:", duragan.length, "canli:", canli.uzunluk);

const yeni = oge("li", { class: "olcum" }, "Rüzgâr hızı");
yeni.ebeveyn = liste;
liste.cocuklar.push(yeni);

console.log("ekleme sonrasi — duragan:", duragan.length, "canli:", canli.uzunluk);
```

```
ekleme oncesi  — duragan: 2 canli: 2
ekleme sonrasi — duragan: 2 canli: 3
```

Durağan liste çağrıldığı andaki eşleşmelerin bir kopyasıdır; ağaç sonradan değişse de
liste değişmez. Canlı koleksiyon ise bir sorgunun kendisidir: her okunduğunda o andaki
eşleşmeleri verir.

Tarayıcı API'sinde `querySelectorAll` durağan, `getElementsByTagName` ve
`getElementsByClassName` canlı sonuç döndürür. Ayrım iki durumda önem kazanır. Birincisi,
canlı bir koleksiyon üzerinde döngü kurarken döngünün gövdesinde öge eklemek ya da
silmek koleksiyonun uzunluğunu döngü sürerken değiştirir; sonsuz döngü buradan çıkar.
İkincisi, durağan bir listeyi uzun süre saklamak, ağaçtan çıkarılmış düğümleri bellekte
tutar — bu, Eşzamansız JavaScript ve Çalışma Zamanı kursundaki Bellek Sızıntısı Tanısı
dersinde tanımlanan erişilebilirlik sorununun bu kurstaki karşılığıdır.

## Öznitelik ve Özellik

Bir ögenin işaretlemede yazılan `href="..."` bildirimi ile program tarafındaki `href`
değeri aynı şey değildir. Birincisi **öznitelik (attribute)**, ikincisi **özellik
(property)** adını alır. Öznitelik ayrıştırıcının kaynak metinden okuduğu dizgidir;
özellik, o dizgiden türetilmiş ve çalışma sırasında değişebilen değerdir.

```js
// oznitelik.mjs — oznitelik dizgisi ile ozellik degeri arasindaki ayrim
const TABAN = "https://ornek.gecerli/istasyon/kuzey-yamac/";

// Oznitelikler her zaman dizgidir; ozellikler cozumlenmis ve yasayan degerlerdir.
const OZELLIK = {
  a: (o) => ({ href: new URL(o.oznitelikler.href, TABAN).href }),
  "input[text]": (o) => ({
    defaultValue: o.oznitelikler.value,        // oznitelikten okunur
    value: o.girilenDeger ?? o.oznitelikler.value, // kullanicinin girdigi deger
  }),
  "input[checkbox]": (o) => ({
    defaultChecked: "checked" in o.oznitelikler,
    checked: o.isaretlendi ?? "checked" in o.oznitelikler,
  }),
};

const ogeler = [
  ["a", { oznitelikler: { href: "../gunluk?tur=sicaklik" } }],
  ["input[text]", { oznitelikler: { name: "deger", value: "-4.2" }, girilenDeger: "-6.8" }],
  ["input[checkbox]", { oznitelikler: { name: "dogrulandi", checked: "" }, isaretlendi: false }],
];

for (const [tur, o] of ogeler) {
  console.log(tur);
  console.log("  oznitelik:", JSON.stringify(o.oznitelikler));
  console.log("  ozellik  :", JSON.stringify(OZELLIK[tur](o)));
}
```

```
a
  oznitelik: {"href":"../gunluk?tur=sicaklik"}
  ozellik  : {"href":"https://ornek.gecerli/istasyon/gunluk?tur=sicaklik"}
input[text]
  oznitelik: {"name":"deger","value":"-4.2"}
  ozellik  : {"defaultValue":"-4.2","value":"-6.8"}
input[checkbox]
  oznitelik: {"name":"dogrulandi","checked":""}
  ozellik  : {"defaultChecked":true,"checked":false}
```

Üç ayrışma biçimi görünür. Bağlantıda öznitelik göreli bir adrestir, özellik ise Bağlantılar
dersinde tanımlanan taban adrese göre çözümlenmiş mutlak adrestir. Metin alanında öznitelik
**başlangıç** değerini taşır ve kullanıcı yazdıkça değişmez; güncel değer yalnızca özellikte
durur. Onay kutusunda öznitelik yalnızca sayfa yüklendiğindeki işaretli olma durumunu
bildirir; kullanıcı kutuyu kaldırdığında öznitelik yerinde kalır, özellik yanlış olur.

Buradan pratik bir kural çıkar: **kullanıcının değiştirebildiği durum özellikten okunur,
belgenin bildirdiği başlangıç durumu öznitelikten.** Form alanının o anki değerini
öznitelikten okuyan kod, kullanıcının yazdığını hiçbir zaman görmez.

Veri Öznitelikleri dersinde tanımlanan `data-` öznitelikleri bu ikiliğin dışındadır:
tanımlı bir özellik karşılıkları olmadığı için her iki yönde de dizgi olarak kalırlar.

## Düğüm Oluşturma ve Yerleştirme

Yeni içerik iki yolla üretilebilir. Birincisi düğümü tek tek kurmaktır: öge oluşturulur,
öznitelikleri yazılır, metin düğümü eklenir, sonra ağaçtaki yerine yerleştirilir. İkincisi
bir işaretleme dizgisi verip ayrıştırıcıya ağaç kurdurmaktır.

İkinci yol kısa yazılır ve bir bedeli vardır: dizginin içine kullanıcıdan gelen bir değer
karışırsa, o değerdeki `<` karakteri etiket olarak yorumlanır. Etiketler, Öznitelikler ve
Varlıklar dersinde tanımlanan kaçırma kuralı burada işletilmediğinde, veri koda dönüşür.
Bu nedenle kullanıcı verisi taşıyan içerik metin düğümü olarak eklenir; metin düğümüne
yazılan `<` karakteri hiçbir koşulda etiket olmaz.

Yerleştirme işlemlerinin ortak bir özelliği vardır: bir düğümün ağaçta tek bir yeri
olabilir. Zaten bağlı bir düğüm başka bir yere eklendiğinde kopyalanmaz, **taşınır**;
eski yerinden kendiliğinden çıkar.

## Toplu Değişikliğin Maliyeti

Ağaca bağlı bir düğümü değiştirmek, biçem ve yerleşim hesabının ilgili bölümünü geçersiz
kılar. Yüz maddelik bir listeyi tek tek eklemek, bu geçersiz kılmayı yüz kez tetikler.
Çözüm, düğümleri belgeye bağlı olmayan bir kapta hazırlamak ve tek seferde bağlamaktır.
Bu kabın adı **belge parçası (document fragment)** dır.

```js
// parca.mjs — tek tek ekleme ile belge parcasiyla ekleme arasindaki fark
const oge = (ad, ozn = {}) => ({ tur: "oge", ad, ozn, cocuklar: [], ebeveyn: null });

let gecersizKilma = 0; // belgeye bagli agacta yapilan her degisiklik bunu artirir

function bagliMi(dugum) {
  let ata = dugum;
  while (ata.ebeveyn) ata = ata.ebeveyn;
  return ata.tur === "belge";
}

// Bir cagri = bir agac degisikligi.
function ekle(hedef, ...dugumler) {
  for (const d of dugumler) { d.ebeveyn = hedef; hedef.cocuklar.push(d); }
  if (bagliMi(hedef)) gecersizKilma += 1;
}

const belge = { tur: "belge", ad: "#belge", cocuklar: [], ebeveyn: null };
const liste = oge("ul", { id: "olcumler" });
ekle(belge, liste);

const kayitlar = ["Sıcaklık", "Bağıl nem", "Rüzgâr hızı", "Yağış", "Basınç"];

// Birinci yol: her madde ayri bir cagriyla bagli agaca eklenir.
gecersizKilma = 0;
for (const ad of kayitlar) ekle(liste, oge("li", { "data-olcum": ad }));
console.log("dogrudan ekleme:", gecersizKilma, "gecersiz kilma,", liste.cocuklar.length, "cocuk");

// Ikinci yol: maddeler once bagli olmayan parcada toplanir, sonra tek cagriyla eklenir.
liste.cocuklar.length = 0;
gecersizKilma = 0;
const parca = { tur: "parca", ad: "#parca", cocuklar: [], ebeveyn: null };
for (const ad of kayitlar) ekle(parca, oge("li", { "data-olcum": ad }));
ekle(liste, ...parca.cocuklar.splice(0));
console.log("parcayla ekleme:", gecersizKilma, "gecersiz kilma,", liste.cocuklar.length, "cocuk");
console.log("parcada kalan  :", parca.cocuklar.length, "cocuk");
```

```
dogrudan ekleme: 5 gecersiz kilma, 5 cocuk
parcayla ekleme: 1 gecersiz kilma, 5 cocuk
parcada kalan  : 0 cocuk
```

Belge parçasının iki özelliği çıktıda görünür. Birincisi, parçaya yapılan eklemeler
belgeye bağlı olmadığı için geçersiz kılma üretmez. İkincisi, parça ağaca eklendiğinde
kendisi ağaca girmez; yalnızca çocuklarını devreder ve boşalır. Son satırdaki sıfır bunu
gösterir.

Buradaki sayı bir başarım ölçümü değil, bir **çağrı sayımıdır**. Gerçek maliyetin ne
kadar olduğu belgeye ve biçeme bağlıdır; ölçülmesi Başarım Kaydı dersinin konusudur. Sabit
olan şey, tetiklenen hesap sayısının beşten bire indiğidir.

## Özet

- Belge ağacı, düğümleri ebeveyn–çocuk–kardeş bağlarıyla bağlı bir nesne grafiğidir; bu
  bağların bir bölümü bütün düğümleri, bir bölümü yalnızca ögeleri görür.
- Etiketler arasındaki girinti ve satır sonları metin düğümü olarak ağaca girer; düğüm
  bağlarıyla gezinen kod işaretlemenin biçimlendirilmesine duyarlıdır.
- Seçme işlemi ya durağan bir liste ya da canlı bir koleksiyon döndürür; canlı koleksiyon
  her okunduğunda ağacı yeniden sorgular.
- Öznitelik kaynak metindeki dizgidir, özellik ondan türetilmiş yaşayan değerdir; kullanıcı
  girdisi yalnızca özellikte görünür.
- Bağlı bir düğüme yapılan her değişiklik biçem ve yerleşim hesabını geçersiz kılar; toplu
  ekleme bağlı olmayan bir belge parçasında hazırlanır.

## Sonraki Adım

Bu ders belgeyi okumayı ve değiştirmeyi kurdu, ancak değişikliği neyin tetikleyeceğini
açık bıraktı. Bir sayfa kendiliğinden değişmez; kullanıcının tıkladığı, yazdığı, kaydırdığı
an bir bildirim üretir ve program o bildirime yanıt verir. Bu bildirimlerin ağaç üzerinde
izlediği yol tanımlıdır ve tek bir düğümden ibaret değildir: olay, hedefe ulaşmadan önce
atalarından geçer ve hedeften sonra aynı yoldan geri döner. Sonraki ders bu üç evreli
yolculuğu ve dinleyicilerin hangi sırayla çağrıldığını inceler.
