Document Object Model (DOM)
The DOM is a programming interface for HTML and XML documents, providing a structured representation that allows programs to dynamically access and modify content, structure, and style.
Core DOM Operations
- Creating Nodes:
document.createElement(),document.createTextNode(),document.createDocumentFragment()(for efficient batch updates), anddocument.createAttribute(). - Querying Nodes:
querySelector(),querySelectorAll(). - Updating Content:
innerHTML,textContent,innerText. - Adding Nodes:
appendChild(),insertBefore(). - Removing Nodes:
removeChild().
Element Visibility Detection
Several methods determine if an element is within the visible browser area.
getBoundingClientRect Approach
function isElementVisible(element) {
const rect = element.getBoundingClientRect();
const viewportHeight = window.innerHeight;
const viewportWidth = window.innerWidth;
return (
rect.top < viewportHeight &&
rect.bottom > 0 &&
rect.left < viewportWidth &&
rect.right > 0
);
}
Intersection Observer Implementation
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log('Element is visible');
}
});
}, {
threshold: 0.5
});
observer.observe(document.querySelector('#target-element'));
Browser Object Model (BOM)
The BOM provides objects representing the browser window and its components, with window as the top-level object.
Key BOM Components
- window: Manages browser windows, including
open(),close(), and scrolling methods likescrollTo(). - location: Represents the current URL with properties like
hash,host,pathname, andsearch. - navigator: Provides browser information such as
geolocationandmediaDevices. - screen: Contains screen dimensions and color depth properties.
- history: Manages session history with methods like
go(),back(), andforward().
JavaScript Data Types
JavaScript distinguishes between primitive and reference types. Primitive types (number, string, boolean, null, undefined, symbol) are stored directly in stack memory, while reference types (objects, arrays, functions) store references to heap memory.
Type Conversion and Detection
Explicit conversion uses methods like Number(), String(), and Boolean(). Implicit conversion occurs during operations like == comparisons. For reliable type detection, Object.prototype.toString.call() provides consistent results.
function determineType(value) {
const baseType = typeof value;
if (baseType !== 'object' && baseType !== 'function') {
return baseType;
}
return Object.prototype.toString.call(value)
.slice(8, -1);
}
Prototype Chain and Inheritance
JavaScript uses prototypal inheritance where objects inherit properties from other objects. Each function has a prototype property, and instances have an internal __proto__ link to the constructor's prototype.
Prototype Chain Example
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name + ' makes a noise.');
};
function Dog(name) {
Animal.call(this, name);
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.speak = function() {
console.log(this.name + ' barks.');
};
const dog = new Dog('Rex');
dog.speak(); // 'Rex barks.'
Event Loop and Asynchronous Execution
JavaScript's single-threaded nature is managed through an event loop that processes tasks in a specific order. Synchronous tasks execute immediately in the main thread, while asynchronous operations (like timers or promises) are handled by the browser's Web APIs and added to the appropriate queue.
Microtasks vs. Macrotasks
Microtasks (e.g., Promise callbacks, queueMicrotask) execute after the current synchronous code completes but before the next macrotask. Macrotasks (e.g., setTimeout, setInterval, I/O) are processed one at a time, with microtasks run between them.
console.log('Start');
setTimeout(() => console.log('Timeout'), 0);
Promise.resolve().then(() => console.log('Promise'));
console.log('End');
This code outputs: Start, End, Promise, Timeout, illustrating the microtask queue's priority over macrotasks.
Event Delegation
Event delegation leverages event bubbling to handle events on a parent element instead of individual child elements, reducing the need for multiple event listeners.
document.getElementById('list').addEventListener('click', (event) => {
if (event.target.matches('li')) {
console.log('Clicked item:', event.target.textContent);
}
});
Debounce and Throttle Techniques
These optimization techniques control the rate of function execution.
Debounce Implementation
function debounce(callback, delay, triggerImmediately) {
let timer;
return function(...parameters) {
const context = this;
if (timer) clearTimeout(timer);
if (triggerImmediately) {
const executeNow = !timer;
timer = setTimeout(() => timer = null, delay);
if (executeNow) callback.apply(context, parameters);
} else {
timer = setTimeout(() => callback.apply(context, parameters), delay);
}
};
}
Throttle Implementation
function throttle(callback, interval) {
let lastCall = 0;
return function(...args) {
const now = Date.now();
if (now - lastCall >= interval) {
callback.apply(this, args);
lastCall = now;
}
};
}
Security Considerations
Front-end developers must be aware of common security vulnerabilities.
Cross-Site Scripting (XSS)
XSS occurs when malicious scripts are injected into web pages. Prevention includes sanitizing user input, using Content Security Policy (CSP), and avoiding unsafe methods like innerHTML with untrusted data.
Cross-Site Request Forgery (CSRF)
CSRF attacks trick users in to executing unwanted actions on a site where they're authenticated. Mitigation involves using anti-CSRF tokens and validating the origin of requests.
Single Sign-On (SSO)
SSO allows users to authenticate once and access multiple related systems. Common implementations include cookie-based sharing for same-domain scenarios and token-based approaches for cross-domain setups using techniques like postMessage with iframes.
Large File Handling
For efficient large file uploads, techniques like chunking and Web Workers are employed to avoid blocking the main thread.
// fileUploader.js (Web Worker)
self.onmessage = function(e) {
const { file, chunkSize } = e.data;
const totalChunks = Math.ceil(file.size / chunkSize);
for (let i = 0; i < totalChunks; i++) {
const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize);
const formData = new FormData();
formData.append('chunk', chunk);
formData.append('index', i);
formData.append('total', totalChunks);
fetch('/upload', { method: 'POST', body: formData })
.then(() => self.postMessage({ index: i, status: 'success' }))
.catch(error => self.postMessage({ index: i, status: 'error', error }));
}
};
// Main thread
const worker = new Worker('fileUploader.js');
worker.postMessage({ file: selectedFile, chunkSize: 1024 * 1024 });
worker.onmessage = (e) => console.log(e.data);