Seriya: JavaScript Basics Dars 53

DOM nima?

DOM nima ekani va nega kerakligi, brauzer HTML'ni qanday parsing qilib DOM daraxtiga aylantirishi, DOM node'larining prototype zanjiri (EventTarget → Node → Element → HTMLElement), va live HTMLCollection bilan static NodeList orasidagi farq.

53-dars

DOM nima?

DOM (Document Object Model) — brauzer HTML faylni o'qib, uni JavaScript orqali boshqarish mumkin bo'lgan obyektlar daraxtiga aylantirgan holati. HTML — bu shunchaki matn fayl, lekin DOM — brauzer xotirasida yaratilgan, tirik (live), dasturiy tuzilma.

<html>
  <body>
    <h1>Salom</h1>
    <p>Bu matn</p>
  </body>
</html>

Brauzer buni o'qib, xotirada shunday daraxt yaratadi:

document
  └── html
        └── body
              ├── h1
              │     └── "Salom" (text node)
              └── p
                    └── "Bu matn" (text node)

Har bir HTML tegi — daraxtdagi bitta node (tugun). Siz JS orqali shu node'larni o'qiy olasiz, o'zgartira olasiz, o'chira olasiz, yangisini qo'sha olasiz — va brauzer buni darhol ekranga chiqaradi.

document.querySelector('h1').textContent = 'Xayr';
// Ekranda "Salom" o'rniga "Xayr" chiqadi — darhol

1. Nega bu kerak bo'lgan?

HTML — statik til. U faqat "bu yerda sarlavha, bu yerda paragraf" deb aytadi, lekin hech narsani o'zgartira olmaydi. Agar foydalanuvchi tugmani bossa, forma to'ldirsa, vaqt o'tsa — sahifa dinamik ravishda o'zgarishi kerak. Buning uchun HTML'ni dasturlash tiliga tushunarli obyektlarga aylantirish kerak edi — shuning uchun DOM yaratilgan (1998, W3C standarti sifatida rasmiylashtirilgan).

Muhim narsa: DOM — JavaScript'ning bir qismi emas. DOM — brauzer taqdim qiladigan alohida API (xuddi oldingi mavzularda ko'rgan Web API'lar kabi — setTimeout, fetch). JS tili o'zi — faqat sintaksis va mantiq (if, for, function). DOM'ni brauzer beradi, Node.js'da esa DOM umuman yo'q (shuning uchun Node'da document.querySelector ishlamaydi — xato beradi).


2. Brauzer darajasida — DOM qanday "jismonan" yaratiladi

Bu jarayon HTML Parsing deyiladi, va u aniq bosqichlarda ketadi:

  1. Bayt oqimi (bytes) — server'dan HTML fayl bayt (0 va 1) shaklida keladi
  2. Belgilar (characters) — bayt kodlash (masalan, UTF-8) orqali belgilarga aylantiriladi: <, h, 1, >...
  3. Token'lar — brauzerning HTML Tokenizeri belgilarni tokenlarga bo'ladi: StartTag: html, StartTag: body, StartTag: h1, Character: Salom, EndTag: h1...
  4. Node'lar — har bir token — **obyekt (node)**ga aylantiriladi, xotirada C++ darajasidagi tuzilma sifatida yaratiladi
  5. DOM Tree — node'lar ota-bola (parent-child) munosabati asosida daraxtga yig'iladi

Bu jarayonni bajaruvchi mexanizm brauzerda HTML Parser deb ataladi (Chrome'da bu qism V8'ning o'zida emas, balki Blink rendering engine ichida joylashgan — V8 faqat JS'ni bajaradi, Blink esa HTML/CSS/DOM bilan ishlaydi).

Muhim jihat: parsing — ketma-ket, yuqoridan pastga boradi. Brauzer HTML'ni bittalab o'qiydi, va agar yo'lda <script> tegi uchrasa — standart holatda parsing to'xtaydi, script yuklanadi va bajariladi, keyin parsing davom etadi. (Shuning uchun <script> odatda </body>dan oldin yoziladi yoki defer/async ishlatiladi — bu keyingi mavzularda, Performance optimization qismida chuqurroq ko'ramiz.)


3. DOM node'lari — ichki tuzilma

Har bir DOM node — aslida JavaScript'dagi oddiy obyekt kabi ko'rinsa ham, aslida u C++ obyekti bo'lib, JS'ga faqat interfeys (binding) orqali ko'rsatiladi:

const h1 = document.querySelector('h1');
console.log(h1 instanceof HTMLElement); // true
console.log(h1 instanceof Node);        // true
console.log(h1 instanceof EventTarget); // true

Bu — meros olish zanjiri (prototype chain), oldingi mavzularda ko'rgan mexanizm, lekin bu yerda zanjir brauzer tomonidan oldindan tayyorlangan:

EventTarget
   └── Node
         └── Element
               └── HTMLElement
                     └── HTMLHeadingElement (h1 uchun)
  • EventTarget — hodisalarni (event) qabul qila olish qobiliyatini beradi (addEventListener)
  • Node — daraxt tuzilmasidagi umumiy xususiyatlar (parentNode, childNodes, nextSibling)
  • Element — faqat HTML/XML elementlariga xos narsalar (getAttribute, classList)
  • HTMLElement — barcha HTML teglariga umumiy (style, innerText, hidden)
  • HTMLHeadingElement — faqat <h1>–<h6> uchun maxsus

Bu — nega document.body.style.color = 'red' ishlaydi-yu, lekin oddiy {} obyektda style yo'qligi tushunarli bo'ladi: style — HTMLElement prototipida oldindan aniqlangan getter/setter orqali ta'minlangan, va u orqaga — real render qatlamiga bog'langan (buni Reflow/Repaint mavzusida ko'ramiz).


4. Muhim tushuncha: DOM — "tirik" (live)

const paragraphs = document.getElementsByTagName('p'); // Live HTMLCollection
console.log(paragraphs.length); // 2

document.body.appendChild(document.createElement('p'));
console.log(paragraphs.length); // 3 — avtomatik yangilandi!

getElementsByTagName — live natija qaytaradi: bu — hujjatning o'ziga to'g'ridan-to'g'ri "deraza" (view), har safar .length chaqirilganda qayta hisoblanadi. Buning aksi — querySelectorAll, u static (snapshot) qaytaradi:

const paragraphs2 = document.querySelectorAll('p'); // Static NodeList
console.log(paragraphs2.length); // 2

document.body.appendChild(document.createElement('p'));
console.log(paragraphs2.length); // 2 — o'zgarmadi, chunki bu — o'sha paytdagi "surat"

Bu farq — amaliyotda muhim performance va bug manbai: live collection'ni loop ichida ishlatib, shu loop ichida DOM'ga element qo'shsangiz, cheksiz loop yoki kutilmagan natija olishingiz mumkin.