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:
- Bayt oqimi (bytes) — server'dan HTML fayl bayt (0 va 1) shaklida keladi
- Belgilar (characters) — bayt kodlash (masalan, UTF-8) orqali belgilarga aylantiriladi:
<,h,1,>... - Token'lar — brauzerning HTML Tokenizeri belgilarni tokenlarga bo'ladi:
StartTag: html,StartTag: body,StartTag: h1,Character: Salom,EndTag: h1... - Node'lar — har bir token — **obyekt (node)**ga aylantiriladi, xotirada C++ darajasidagi tuzilma sifatida yaratiladi
- 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.