JavaScript, DOM form the cornerstone of modern front-end development interviews. This combination tests candidates' understanding of client-side logic, component-based architecture, and direct manipulation of the browser environment. These topics are commonly evaluated at intermediate levels companies ranging from startups giants like Amazon, Google, and Facebook as they reflect real-world application development skills.
JavaScript is a high-level, dynamic programming language primarily used for web development to create interactive, client-side applications.
// Closure example function outer() { let count = 0; return function inner() { count++; return count; }; } const increment = outer(); console.log(increment()); // 1 console.log(increment()); // 2
React is a JavaScript library for building user interfaces, emphasizing component-based architecture and declarative UI.
useState, useEffect, etc.) that enable state and side effects in functional components.import React, { useState, useEffect } from 'react'; function Counter() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); // Dependency array return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
The Document Object Model (DOM) is a programming interface for HTML and XML documents. It represents the page so programs can alter the document structure, style, and content.
querySelector(), createElement(), appendChild(), classList, etc.addEventListener() and manage events like clicks, keyboard input.// Vanilla DOM example: Toggle a class on click const button = document.querySelector('#toggleBtn'); const element = document.getElementById('target'); button.addEventListener('click', () => { element.classList.toggle('highlight'); });
Explain how closures work in JavaScript and provide a practical use case.
function createCounter() { let count = 0; return { increment: () => ++count, getValue: () => count }; } const counter = createCounter(); console.log(counter.getValue()); // 0 counter.increment(); console.log(counter.getValue()); // 1
What is the purpose of the useEffect hook in React? How would you handle side effects and dependencies?
useEffect performs side effects in functional components (e.g., data fetching, subscriptions).
useEffect(callback, dependencies)[]: Run once after initial render.[dep]: Re-run when dep changes.useEffect(() => { fetchData(props.userId); return () => { /* Cleanup (e.g., unsubscribe) */ }; }, [props.userId]); // Only re-run if userId changes
How does React’s reconciliation algorithm work? What factors determine whether an element is updated?
<div> → <span>) trigger rebuilds.What are the differences between controlled and uncontrolled components in React?
defaultValue → value).defaultValue only; access via ref).// Controlled function Input() { const [value, setValue] = useState(''); return <input value={value} onChange={e => setValue(e.target.value)} />; } // Uncontrolled function Input() { const inputRef = useRef(null); return <input defaultValue="Initial" ref={inputRef} />; }
Why is direct DOM manipulation discouraged in React? What are the alternatives?
ReactDOM.createPortal) for modals/overlays.Create a useFetch hook that handles data fetching, loading states, and errors.
import { useState, useEffect } from 'react'; function useFetch(url) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchData = async () => { try { const response = await fetch(url); if (!response.ok) throw new Error('Network response was not ok'); const result = await response.json(); setData(result); } catch (err) { setError(err.message); } finally { setLoading(false); } }; fetchData(); }, [url]); return { data, loading, error }; } // Usage in component function UserProfile({ userId }) { const { data, loading, error } = useFetch(`https://api.example.com/users/${userId}`); if (loading) return <p>Loading...</p>; if (error) return <p>Error: {error}</p>; return <div>{data.name}</div>; }
useState for data, loading, and error states.url changes (dependency array).requestAnimationFrameAnimate a ball’s position smoothly without jitter.
function animateBall() { const ball = document.getElementById('ball'); let position = 0; function update() { position += 1; ball.style.left = `${position}px`; if (position < window.innerWidth - 50) { // Stop before edge requestAnimationFrame(update); } } update(); } // Trigger animation on button click document.getElementById('startBtn').addEventListener('click', animateBall);
Easy: Explain the output of the following closure code:
function test() { let count = 0; return function() { return ++count; }; } const t = test(); console.log(t()); console.log(t());
Hint: Understand how lexical scoping and closure retain access to
count.
Medium: Implement a React component that fetches and displays a random joke from an API, with error handling and a refresh button.
Hint: Use
useEffect,useState, anduseReffor cleanup/abort controller.
Intermediate: Build a vanilla JS function that efficiently adds thousand separators to a numeric string (e.g., 1234567 → 1,234,567) without using toLocaleString().
Hint: Use regular expressions or string manipulation in reverse.
requestAnimationFrame for animations.setCount(prev => prev + 1)).useEffect (causes infinite loops).Study Tip: Implement the practice problems manually, then compare your solution with optimized versions. Focus on readability and edge cases!
<div>, <p>), text nodes ("Hello World"), attributes (class="container"), or comments.Document
└── <body>
├── <header>
│ └── <nav>...</nav>
└── <main>
└── <p id="target">Dynamic Content</p>
| Method | Purpose | Example |
|---|---|---|
document.getElementById() | Selects an element by its id attribute | const el = document.getElementById('header'); |
document.querySelector() | Selects the first element matching a CSS selector | const btn = document.querySelector('.btn-primary'); |
element.querySelectorAll() | Returns all elements matching a CSS selector | const links = document.querySelectorAll('a'); |
element.createElement() | Creates a new HTML element | const newDiv = document.createElement('div'); |
element.appendChild() | Adds a node as the last child of an element | div.appendChild(newDiv); |
element.removeChild() | Removes a child node from an element | div.removeChild(oldDiv); |
element.classList | Toggles, adds, or removes CSS classes | btn.classList.add('active'); |
element.style | Directly modifies inline CSS styles | el.style.backgroundColor = 'red'; |
element.setAttribute() | Sets or updates an HTML attribute | img.setAttribute('src', 'image.jpg'); |
element.textContent | Gets or sets the text content of an element (ignores HTML tags) | para.textContent = 'Hello'; |
element.innerHTML | Gets or sets HTML content (allows HTML injection) | div.innerHTML = '<span>Bold</span>'; |
element.addEventListener() | Attaches an event listener (e.g., clicks, keypresses) | btn.addEventListener('click', handleClick); |
click, keypress, submit) trigger functions when user interactions occur.removeEventListener to avoid memory leaks.Example: Event Handling
const button = document.getElementById('myBtn'); function handleClick() { alert('Button clicked!'); } // Add listener button.addEventListener('click', handleClick); // Remove listener (cleanup) button.removeEventListener('click', handleClick);
Direct DOM manipulation is expensive because each change can trigger reflows (redesigning the page layout) and repaints (redrawing CSS/visual changes). Follow these rules to optimize:
requestAnimationFrame()offsetHeight, clientWidth) before making changes and after changes.// Bad: Read + write pattern (causes layout thrashing) const height = div.offsetHeight; div.style.height = '500px'; // Good: Batch writes div.style.height = '500px';
Document Fragment Example
const fragment = document.createDocumentFragment(); for (let i = 0; i < 100; i++) { const p = document.createElement('p'); p.textContent = `Item ${i}`; fragment.appendChild(p); } document.body.appendChild(fragment); // Single DOM operation
| Aspect | Vanilla JavaScript | React |
|---|---|---|
| Approach | Imperative: Manually update the DOM | Declarative: Define what the UI should look like; React handles the how |
| Updates | Direct manipulation (e.g., element.textContent = '...') | Re-render components based on state/props changes |
| Performance | Risk of inefficient updates | Virtual DOM diffing optimizes updates |
| Event Handling | addEventListener attached to DOM elements | Synthetic event system (onClick, onChange) wrapped by React |
| State Management | Manual (e.g., storing data in variables) | Built-in state hooks (useState, useReducer) |
Example: React’s Declarative Approach
function Counter() { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
React automatically updates the DOM when count changes—no manual DOM manipulation required.
width, padding).backgroundColor).offsetHeight, getBoundingClientRect() → force reflow.style properties → repaint.innerHTML, textContent, and innerText.innerHTML: Parses and inserts HTML strings (Potentially unsafe due to XSS).element.innerHTML = '<img src="x">';textContent: Sets raw text (ignores HTML tags). Fast and safe.element.textContent = '<img src="x">'; → renders as plaintext.innerText: Returns rendered visible text (respects CSS display:none).innerHTML for dynamic updates?innerHTML overwrites content.textContent, createElement, or React’s JSX rendering.textContent over innerHTML for text-only updates (security + performance).requestAnimationFrame.document.getElementById) unless absolutely necessary (e.g., integrating third-party libraries).</details>Tip: Always ask clarifying questions during interviews about constraints (e.g., "Is this a React app or vanilla JS?") before diving into solutions.
Start a new session to explore different topics or increase the difficulty level.
Start New Session