DOM and BOM Interview Guide - JavaScript
DOM and BOM Interview Guide - JavaScript
Table of Contents
1. DOM Fundamentals
2. DOM Selection Methods
3. DOM Manipulation
4. Event Handling
5. DOM Traversal
6. BOM (Browser Object Model)
7. Storage APIs
9. Performance Optimization
DOM Fundamentals
What is DOM?
The Document Object Model (DOM) is a programming interface that represents HTML/XML documents
as a tree structure of objects that can be manipulated with JavaScript.
javascript
// DOM Tree Example
/*
Document
└── html
├── head
│ ├── title
│ └── meta
└── body
├── div (id="container")
│ ├── p (class="text")
│ └── span
└── script
*/
Node Types
javascript
getElementById
javascript
// Select by ID (returns single element or null)
const element = document.getElementById('myId');
if (element) {
console.log('Element found:', element);
}
getElementsByClassName
javascript
getElementsByTagName
javascript
javascript
// Complex selectors
const complexSelect = document.querySelector('div > p:first-child');
javascript
// Select all matching elements (returns NodeList)
const elements = document.querySelectorAll('.myClass');
const allDivs = document.querySelectorAll('div');
javascript
DOM Manipulation
Creating Elements
javascript
// Create new elements
const div = document.createElement('div');
const textNode = document.createTextNode('Hello World');
const fragment = document.createDocumentFragment();
// Using setAttribute
div.setAttribute('data-id', '123');
div.setAttribute('aria-label', 'Container');
javascript
// Append methods
const parent = document.getElementById('container');
const child = document.createElement('p');
child.textContent = 'New paragraph';
// Modern methods
parent.append(child); // Can append multiple nodes/strings
parent.prepend(child); // Add to beginning
parent.before(child); // Insert before parent
parent.after(child); // Insert after parent
Modifying Content
javascript
const element = document.getElementById('myDiv');
Modifying Attributes
javascript
// Get attributes
const id = element.getAttribute('id');
const className = element.getAttribute('class');
// Set attributes
element.setAttribute('data-value', '100');
element.setAttribute('title', 'Tooltip text');
// Remove attributes
element.removeAttribute('title');
Modifying Styles
javascript
// Inline styles
element.style.color = 'red';
element.style.backgroundColor = 'blue';
element.style.fontSize = '16px';
// CSS classes
element.className = 'new-class'; // Replace all classes
element.classList.add('class1', 'class2'); // Add classes
element.classList.remove('class1'); // Remove class
element.classList.toggle('active'); // Toggle class
element.classList.contains('active'); // Check if class exists
element.classList.replace('old-class', 'new-class'); // Replace class
Removing Elements
javascript
const element = document.getElementById('myDiv');
// Modern method
element.remove(); // Removes element from DOM
// Legacy method
element.parentNode.removeChild(element);
Event Handling
javascript
// addEventListener (recommended)
const button = document.getElementById('myButton');
function handleClick(event) {
console.log('Button clicked!');
console.log('Event type:', event.type);
console.log('Target:', event.target);
console.log('Current target:', event.currentTarget);
}
button.addEventListener('click', handleClick);
// With options
button.addEventListener('click', handleClick, {
once: true, // Execute only once
passive: true, // Never calls preventDefault
capture: true // Capture phase
});
// Arrow function
button.addEventListener('click', (e) => {
console.log('Arrow function handler');
});
javascript
function handleEvent(event) {
// Prevent default behavior
event.preventDefault();
// Event properties
console.log('Type:', event.type);
console.log('Target:', event.target); // Element that triggered event
console.log('Current Target:', event.currentTarget); // Element with listener
console.log('Timestamp:', event.timeStamp);
// Mouse events
if (event.type.startsWith('mouse')) {
console.log('Client X:', event.clientX);
console.log('Client Y:', event.clientY);
console.log('Page X:', event.pageX);
console.log('Page Y:', event.pageY);
console.log('Button:', event.button); // 0=left, 1=middle, 2=right
}
// Keyboard events
if (event.type.startsWith('key')) {
console.log('Key:', event.key);
console.log('Code:', event.code);
console.log('Ctrl:', event.ctrlKey);
console.log('Shift:', event.shiftKey);
console.log('Alt:', event.altKey);
}
}
javascript
// HTML structure: div > button
const div = document.getElementById('container');
const button = document.getElementById('myButton');
// Capturing phase
div.addEventListener('click', () => console.log('Div clicked (capturing)'), true);
button.addEventListener('click', () => console.log('Button clicked (capturing)'), true);
// Order: Div capturing -> Button capturing -> Button bubbling -> Div bubbling
Event Delegation
javascript
container.addEventListener('click', function(event) {
// Check if clicked element matches selector
if (event.target.matches('.item-button')) {
console.log('Item button clicked:', event.target.textContent);
}
// Or check by class
if (event.target.classList.contains('delete-btn')) {
const item = event.target.closest('.item');
item.remove();
}
});
Custom Events
javascript
// Create custom event
const customEvent = new CustomEvent('myCustomEvent', {
detail: { message: 'Hello from custom event!' },
bubbles: true,
cancelable: true
});
// Alternative syntax
const simpleEvent = new Event('simpleEvent');
document.dispatchEvent(simpleEvent);
javascript
function clickHandler() {
console.log('Clicked!');
}
// Add listener
button.addEventListener('click', clickHandler);
button.addEventListener('click', clickHandler, {
signal: controller.signal
});
Parent Relationships
javascript
// Parent relationships
console.log(element.parentNode); // Direct parent (any node type)
console.log(element.parentElement); // Parent element (null if parent is not element)
console.log(element.closest('.container')); // Closest ancestor matching selector
Child Relationships
javascript
Sibling Relationships
javascript
const element = document.getElementById('middle');
while (sibling) {
if (sibling !== element) {
siblings.push(sibling);
}
sibling = sibling.nextElementSibling;
}
return siblings;
}
javascript
// TreeWalker for complex traversal
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT,
{
acceptNode: function(node) {
return node.classList.contains('highlight')
? NodeFilter.FILTER_ACCEPT
: NodeFilter.FILTER_SKIP;
}
}
);
let node;
while (node = walker.nextNode()) {
console.log(node);
}
// NodeIterator
const iterator = document.createNodeIterator(
document.body,
NodeFilter.SHOW_TEXT
);
let textNode;
while (textNode = iterator.nextNode()) {
console.log(textNode.textContent.trim());
}
Window Object
javascript
// Window properties
console.log(window.innerWidth); // Viewport width
console.log(window.innerHeight); // Viewport height
console.log(window.outerWidth); // Browser window width
console.log(window.outerHeight); // Browser window height
console.log(window.screenX); // Window position X
console.log(window.screenY); // Window position Y
// Window methods
window.alert('Alert message');
window.confirm('Confirm this action?');
const userInput = window.prompt('Enter your name:');
// Open/close windows
const newWindow = window.open('https://example.com', '_blank', 'width=800,height=600');
newWindow.close();
// Scroll methods
window.scrollTo(0, 100); // Scroll to position
window.scrollBy(0, 50); // Scroll by amount
document.getElementById('element').scrollIntoView(); // Scroll element into view
Location Object
javascript
// Navigation methods
location.assign('https://example.com'); // Navigate to URL
location.replace('https://example.com'); // Replace current page in history
location.reload(); // Reload page
location.reload(true); // Force reload from server
javascript
// History navigation
history.back(); // Go back one page
history.forward(); // Go forward one page
history.go(-2); // Go back 2 pages
history.go(1); // Go forward 1 page
// History length
console.log(history.length); // Number of entries in history
Navigator Object
javascript
// Browser information
console.log(navigator.userAgent); // Browser user agent string
console.log(navigator.platform); // Operating system
console.log(navigator.language); // Preferred language
console.log(navigator.languages); // Array of languages
console.log(navigator.cookieEnabled); // Cookies enabled
console.log(navigator.onLine); // Online status
// Geolocation API
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
function(position) {
console.log('Latitude:', position.coords.latitude);
console.log('Longitude:', position.coords.longitude);
},
function(error) {
console.log('Geolocation error:', error.message);
}
);
}
// Clipboard API
if (navigator.clipboard) {
navigator.clipboard.writeText('Text to copy').then(() => {
console.log('Text copied to clipboard');
});
navigator.clipboard.readText().then(text => {
console.log('Clipboard content:', text);
});
}
Screen Object
javascript
// Screen information
console.log(screen.width); // Screen width
console.log(screen.height); // Screen height
console.log(screen.availWidth); // Available screen width
console.log(screen.availHeight); // Available screen height
console.log(screen.colorDepth); // Color depth
console.log(screen.pixelDepth); // Pixel depth
console.log(screen.orientation.angle); // Screen orientation angle
Timers
javascript
// Cancel timeout
clearTimeout(timeoutId);
// Cancel interval
clearInterval(intervalId);
// Cancel animation
cancelAnimationFrame(animationId);
Storage APIs
localStorage
javascript
// Store data (persists until manually cleared)
localStorage.setItem('username', 'john_doe');
localStorage.setItem('preferences', JSON.stringify({theme: 'dark', lang: 'en'}));
// Retrieve data
const username = localStorage.getItem('username');
const preferences = JSON.parse(localStorage.getItem('preferences') || '{}');
// Remove item
localStorage.removeItem('username');
// Clear all
localStorage.clear();
sessionStorage
javascript
Cookies (Legacy)
javascript
// Set cookie
document.cookie = "username=john_doe; expires=Thu, 18 Dec 2024 12:00:00 UTC; path=/";
function getCookie(name) {
const nameEQ = name + "=";
const ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
function deleteCookie(name) {
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
}
MutationObserver
javascript
// Observe DOM changes
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log('Mutation type:', mutation.type);
// Start observing
const targetNode = document.getElementById('observeMe');
observer.observe(targetNode, {
childList: true, // Observe child additions/removals
attributes: true, // Observe attribute changes
attributeOldValue: true, // Include old attribute values
subtree: true, // Observe descendants too
characterData: true // Observe text content changes
});
// Stop observing
observer.disconnect();
Intersection Observer
javascript
// Observe element visibility
const intersectionObserver = new IntersectionObserver(function(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log('Element is visible:', entry.target);
// Lazy load images, trigger animations, etc.
} else {
console.log('Element is not visible:', entry.target);
}
});
}, {
threshold: 0.5, // Trigger when 50% visible
rootMargin: '10px' // Margin around the root
});
ResizeObserver
javascript
// Observe element
const resizableElement = document.getElementById('resizable');
resizeObserver.observe(resizableElement);
Shadow DOM
javascript
// Create shadow DOM
const hostElement = document.getElementById('shadow-host');
const shadowRoot = hostElement.attachShadow({mode: 'open'}); // or 'closed'
shadow.innerHTML = `
<style>
:host {
display: block;
padding: 10px;
border: 1px solid #ccc;
}
</style>
<slot></slot>
`;
}
}
customElements.define('my-custom-element', MyCustomElement);
Performance Optimization
Document Fragments
javascript
// Efficient way to add multiple elements
const fragment = document.createDocumentFragment();
javascript
javascript
// Debounce function
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Throttle function
function throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// Usage examples
const searchInput = document.getElementById('search');
const debouncedSearch = debounce(function(event) {
console.log('Searching for:', event.target.value);
}, 300);
searchInput.addEventListener('input', debouncedSearch);
window.addEventListener('scroll', throttledScroll);
javascript
// Basic virtual scrolling implementation
class VirtualList {
constructor(container, items, itemHeight) {
this.container = container;
this.items = items;
this.itemHeight = itemHeight;
this.visibleCount = Math.ceil(container.clientHeight / itemHeight);
this.scrollTop = 0;
this.render();
this.bindEvents();
}
render() {
const startIndex = Math.floor(this.scrollTop / this.itemHeight);
const endIndex = Math.min(startIndex + this.visibleCount, this.items.length);
this.container.innerHTML = html;
this.container.style.paddingTop = `${startIndex * this.itemHeight}px`;
this.container.style.paddingBottom = `${(this.items.length - endIndex) * this.itemHeight}px`;
}
bindEvents() {
this.container.addEventListener('scroll', () => {
this.scrollTop = this.container.scrollTop;
this.render();
});
}
}
// Usage
const items = Array.from({length: 10000}, (_, i) => `Item ${i}`);
const virtualList = new VirtualList(document.getElementById('list'), items, 30);
javascript
const element = document.createElement('div');
element.innerHTML = '<span>Hello <strong>World</strong></span>';
// Key differences:
// - innerHTML: Gets/sets HTML content (can execute scripts)
// - textContent: Gets/sets text content (ignores styling, includes hidden text)
// - innerText: Gets/sets text content (considers styling, excludes hidden text)
javascript
document.getElementById('parent').addEventListener('click', () => {
console.log('Parent clicked (bubbling)');
}, false); // false = bubbling phase
document.getElementById('child').addEventListener('click', () => {
console.log('Child clicked (bubbling)');
}, false);
document.getElementById('parent').addEventListener('click', () => {
console.log('Parent clicked (capturing)');
}, true); // true = capturing phase
// Order with capturing: Parent (capturing) -> Child -> Parent (bubbling)
javascript
// Problem: Event