Dasar DOM ngajarin kamu cara baca-tulis elemen satu-satu. Tapi pas aplikasi membesar — list to-do dengan 100 item, chat dengan ribuan pesan — pendekatan satu-satu jadi lambat dan ribet. DOM Advanced kasih kamu tools profesional: traversal antar elemen, manipulasi class lewat classList, dan pattern paling penting — event delegation yang ngirit listener via satu listener di parent.
💡 Aturan performa #1. Querying DOM itu mahal.
document.querySelector()di dalam loop yang jalan 1000 kali = bottleneck. Cache query sekali di luar loop, terus pake variabelnya. Trick simpel yang bisa bikin app kamu 10x lebih responsive.
Membuat dan menambahkan elemen:
const li = document.createElement("li");
li.textContent = "Item Baru";
document.querySelector("ul").appendChild(li);
Menghapus elemen:
const item = document.querySelector("#hapus-ini");
item.parentNode.removeChild(item);
// atau cara modern:
item.remove();
DOM Traversal — navigasi antar elemen:
const elemen = document.querySelector(".aktif");
elemen.parentNode; // elemen induk
elemen.children; // semua anak langsung
elemen.nextElementSibling; // saudara berikutnya
elemen.previousElementSibling; // saudara sebelumnya
classList — kelola class CSS:
const box = document.querySelector(".box");
box.classList.add("aktif"); // tambah class
box.classList.remove("aktif"); // hapus class
box.classList.toggle("aktif"); // toggle (tambah/hapus)
box.classList.contains("aktif"); // cek apakah ada (true/false)
Event Delegation — pasang event di parent:
const menu = document.querySelector("ul");
menu.addEventListener("click", function(event) {
if (event.target.tagName === "LI") {
// toggle class "aktif" pada li yang diklik
event.target.classList.toggle("aktif");
}
});
Event delegation efisien karena hanya butuh satu event listener di parent, bukan satu per anak. Ini juga otomatis bekerja untuk elemen yang ditambahkan secara dinamis.
🎭 Analogi sehari-hari
Event delegation = satu satpam di pintu gerbang kantor yang nanya semua yang masuk: "kamu mau ke ruangan mana?". Lebih efisien dari pasang satpam di setiap ruangan. Plus kalau ada ruangan baru dibuat (elemen baru), satpam pintu otomatis melayani.
⚠️ Jebakan yang sering ditemui
1. querySelector return null kalau tidak ketemu.
const x = document.querySelector(".tidak-ada");
x.textContent = "halo"; // ❌ TypeError: Cannot read properties of null
x?.textContent && (x.textContent = "halo"); // ✅ optional chaining
2. event.target vs event.currentTarget — beda!
parent.addEventListener("click", e => {
e.target; // elemen yang DIKLIK (bisa anak)
e.currentTarget; // elemen yang PASANG listener (parent)
});
3. innerHTML = "..." BAHAYA dengan input user — XSS.
div.innerHTML = userInput; // ❌ kalau userInput = "<script>...</script>"
div.textContent = userInput; // ✅ aman, di-escape otomatis
4. Query DOM di loop = lambat.
for (let i = 0; i < 100; i++) {
document.querySelector("#x").style.color = "red"; // ❌ query 100x
}
const x = document.querySelector("#x");
for (let i = 0; i < 100; i++) {
x.style.color = "red"; // ✅ query sekali
}
5. appendChild dengan elemen yang sudah ada di DOM = pindahkan, bukan duplikat.
🎯
querySelectorvsgetElementByIdvsquerySelectorAll— pilih yang mana?
- Cari satu elemen by ID →
getElementById("nav")(tercepat, 5x faster dari querySelector)- Cari satu elemen by class/tag/attr/kombinasi →
querySelector(".btn")(CSS selector flexible)- Cari MULTIPLE elemen →
querySelectorAll(".item")(return NodeList — perlu spread[...]atau forEach)- Cari child dari parent specific →
parent.querySelector(".child")(scoped, lebih efisien dari global)- Live update collection →
getElementsByClassName(auto-update saat DOM berubah, jarang dipake)Aturan modern:
querySelector99% kasus karena flexible.getElementByIdcuma kalau perf-critical loop.querySelectorAllreturn STATIC NodeList — gak update otomatis (beda dari getElementsByClassName).
TL;DR: DOM Advanced = traversal (parentNode/children/nextElementSibling), classList (add/remove/toggle/contains), dan event delegation (1 listener di parent ganti N listener di anak — bonus: auto-handle elemen yang nambah dinamis). event.target = yang diklik, event.currentTarget = yang pasang listener. Cache query di luar loop (jangan query 100x). Hindari innerHTML dengan user input (XSS) — pakai textContent.