DOM & Browser
The DOM (Document Object Model) is the live tree of objects the browser turns HTML markup into. JavaScript does not work with the page text directly: it finds nodes of this tree, reads and changes their properties, and attaches event listeners to them. Understanding the DOM means knowing how a lookup by id differs from one by CSS selector, why innerHTML is dangerous for untrusted data, and how a single event travels through all of an element's ancestors.
The topic gathers four layers: finding and changing nodes, the attribute/property distinction, the event model (registration, the Event object, the three propagation phases, delegation, canceling), and custom elements with their lifecycle. The traps here are practical — from wiping classes via className to an XSS injection. The full map is below.
Topic map
- Selecting elements —
getElementById,querySelector, andquerySelectorAll; a staticNodeListversus a live collection. - Changing content —
textContent,innerHTML,style, attributes, andclassList, plus the XSS risk of inserting markup. - Attributes versus properties — the source-markup string versus the live value on the DOM object; why
classmaps toclassName. - Event handling —
addEventListener, theEventobject, andremoveEventListenerby the same reference. - Event propagation — the three phases, bubbling and capturing, delegation, and canceling the flow (
preventDefault,stopPropagation). - Custom elements —
customElements.define, lifecycle callbacks, and encapsulation via shadow DOM.
Common traps
| Mistake | Consequence |
|---|---|
Treating querySelectorAll as a live collection | It is a static NodeList — it does not update on DOM changes |
Expecting null from querySelectorAll on no matches | It returns an empty list, not null |
Assigning className for one class | Wipes all other classes; use classList.add |
Inserting untrusted text via innerHTML | Opens an XSS injection; for text use textContent |
Expecting getAttribute('value') to give typed text | It yields the source markup, not the live input.value property |
| Assuming attribute and property names match | class → className, for → htmlFor, and so on |
Thinking a second addEventListener overwrites the first | It adds another handler; both fire |
| Passing an anonymous function then removing it | removeEventListener needs the same function reference |
Confusing target with currentTarget | target is where the event originated, currentTarget where the listener sits |
| Thinking capturing goes up | The reverse: capturing goes down to the target, bubbling goes up from it |
Expecting return false in addEventListener to cancel the default | Works only in an inline handler; in a callback you need preventDefault |
| Forgetting the hyphen in a custom element name | customElements.define requires a hyphenated name |
Interview relevance
The DOM is asked to check whether you work with the tree deliberately or by guesswork. A candidate who explains delegation as "one listener on an ancestor catches events from all descendants via bubbling, including ones added later" gets ahead of one who attaches a handler to every list row.
Typical checks:
- The difference between
getElementById/querySelector/querySelectorAlland the static vs live nature of the result. - The difference between
textContent/innerHTMLand why the latter is dangerous for untrusted data. - The difference between an HTML attribute and a DOM property; the name mismatch (
class/className). - How
addEventListenerregisters a handler and what is on theEventobject. - The three propagation phases, that bubbling is the default, and how delegation works.
- The difference between
preventDefault,stopPropagation, andstopImmediatePropagation.
Common wrong answer: "querySelectorAll returns a live collection that updates itself when elements are added". In fact it is static — a snapshot at call time; the live ones are the HTMLCollection from getElementsByClassName and getElementsByTagName.