Web Developer
$85K–$150K
US Salary Range
HTML & CSS Fundamentals
Semantic HTML5 Elements
Semantic elements describe their meaning to the browser and developer. They improve accessibility and SEO:
| Element |
Purpose |
Use Case |
| <header> |
Page or section header |
Logo, nav, introductory content |
| <nav> |
Navigation links |
Main menu, breadcrumbs |
| <main> |
Main content (only one per page) |
Page's primary content |
| <section> |
Thematic grouping |
Chapters, numbered sections |
| <article> |
Self-contained content |
Blog post, forum post, news item |
| <aside> |
Sidebar content |
Related links, ads, callouts |
| <footer> |
Page or section footer |
Copyright, contact, links |
CSS Box Model
Every element consists of content, padding, border, and margin (outside in):
/* Content → Padding → Border → Margin */
.box {
width: 200px;
padding: 20px;
border: 2px solid #ccc;
margin: 10px;
}
CSS Specificity
| Selector Type |
Points |
Example |
| Inline style |
1000 |
style="color: red;" |
| ID selector |
100 |
#header |
| Class/Pseudo-class |
10 |
.btn, :hover |
| Element selector |
1 |
div, p, a |
!important overrides everything (use sparingly): color: red !important;
Flexbox Complete Guide
.flex-container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 15px;
}
.flex-item {
flex: 1;
flex-grow: 1;
flex-shrink: 1;
flex-basis: 200px;
}
CSS Grid
.grid-container {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
grid-template-rows: auto 200px auto;
grid-gap: 20px;
grid-auto-fit: auto-fit;
}
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
Responsive Design
.container {
width: 100%;
padding: 15px;
}
@media (min-width: 768px) {
.container { width: 750px; }
}
@media (min-width: 1024px) {
.container { width: 960px; }
}
CSS Variables & BEM Naming
:root {
--color-primary: #6c63ff;
--color-secondary: #00d4aa;
--spacing-unit: 8px;
}
.button {
background: var(--color-primary);
padding: calc(var(--spacing-unit) * 2);
}
.card { }
.card__header { }
.card__header--active { }
Pseudo-classes vs Pseudo-elements
| Type |
Example |
Purpose |
| Pseudo-class (:) |
:hover, :focus, :nth-child(n) |
Element state/position |
| Pseudo-element (::) |
::before, ::after |
Style part of element |
CSS Animations
@keyframes slideIn {
0% {
transform: translateX(-100%);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
.element {
animation: slideIn 0.5s ease-in-out 0.2s forwards;
}
JavaScript (ES6+) — Deep Dive
var vs let vs const
| Keyword |
Scope |
Hoisting |
Reassign |
Redeclare |
| var |
Function |
Hoisted (undefined) |
Yes |
Yes |
| let |
Block |
Hoisted (TDZ) |
Yes |
No |
| const |
Block |
Hoisted (TDZ) |
No |
No |
Closures - Deep Dive
function makeCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = makeCounter();
console.log(counter());
console.log(counter());
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
for (var i = 0; i < 3; i++) {
((j) => {
setTimeout(() => console.log(j), 100);
})(i);
}
Arrow Functions
const greet = (name) => `Hello, ${name}`;
const obj = {
name: 'John',
getName: function() {
const arrow = () => this.name;
return arrow();
}
};
obj.getName();
Event Loop Explained
console.log('1: Start');
setTimeout(() => console.log('4: setTimeout'), 0);
Promise.resolve()
.then(() => console.log('3: Promise.then'));
queueMicrotask(() => console.log('2: queueMicrotask'));
console.log('1: End');
Prototypal Inheritance
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
return `${this.name} makes sound`;
};
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.speak = function() {
return `${this.name} barks`;
};
const dog = new Dog('Rex', 'Labrador');
console.log(dog.speak());
Destructuring & Spread Operator
const [a, b, ...rest] = [1, 2, 3, 4];
const { name, age = 18 } = { name: 'John', age: 25 };
const arr1 = [1, 2];
const arr2 = [...arr1, 3, 4];
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 };
Array Methods Deep Dive
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);
const sum = numbers.reduce((acc, n) => acc + n, 0);
const found = numbers.find(n => n > 1);
const allPositive = numbers.every(n => n > 0);
const hasEven = numbers.some(n => n % 2 === 0);
Promises & async/await
const fetchData = new Promise((resolve, reject) => {
setTimeout(() => resolve('data'), 1000);
});
fetchData
.then(data => console.log(data))
.catch(err => console.error(err))
.finally(() => console.log('done'));
async function getData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
return data;
} catch (error) {
console.error(error);
}
}
Promise.all([p1, p2, p3]);
Promise.race([p1, p2]);
Promise.allSettled([p1, p2]);
Deep Clone Approaches
const original = { a: 1, b: { c: 2 } };
const shallow = { ...original };
shallow.b.c = 3;
const deepClone = JSON.parse(JSON.stringify(obj));
const deepClone2 = structuredClone(obj);
function deepClone(obj, map = new WeakMap()) {
if (map.has(obj)) return map.get(obj);
if (typeof obj !== 'object' || obj === null) return obj;
const cloned = Array.isArray(obj) ? [] : {};
map.set(obj, cloned);
for (const key in obj) {
cloned[key] = deepClone(obj[key], map);
}
return cloned;
}
React — Complete Reference
JSX to React.createElement
const element = <div className="container">
<h1>Hello</h1>
</div>;
const element = React.createElement(
'div',
{ className: 'container' },
React.createElement('h1', null, 'Hello')
);
Functional Component with useState
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(prevCount => prevCount + 1);
};
return (
<>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</>
);
}
useEffect Hook
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
const response = await fetch('/api/data');
const result = await response.json();
setData(result);
setLoading(false);
};
fetchData();
return () => {
};
}, []);
if (loading) return <div>Loading...</div>;
return <div>{JSON.stringify(data)}</div>;
}
Custom Hook Example
function useFetch(url) {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let isMounted = true;
fetch(url)
.then(res => res.json())
.then(data => {
if (isMounted) setData(data);
})
.catch(err => {
if (isMounted) setError(err);
})
.finally(() => {
if (isMounted) setLoading(false);
});
return () => {
isMounted = false;
};
}, [url]);
return { data, error, loading };
}
useReducer for Complex State
const initialState = { count: 0, error: null };
function reducer(state, action) {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
case 'DECREMENT':
return { ...state, count: state.count - 1 };
case 'ERROR':
return { ...state, error: action.payload };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })>+</button>
</div>
);
}
useContext & Context API
const ThemeContext = React.createContext('light');
function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<Header />
<Content />
</ThemeContext.Provider>
);
}
function Header() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
);
}
useMemo vs useCallback
function ExpensiveComponent({ data }) {
const filtered = useMemo(() => {
return data.filter(item => item.active);
}, [data]);
return <List items={filtered} />;
}
function Parent() {
const handleClick = useCallback(() => {
console.log('clicked');
}, []);
return <Button onClick={handleClick} />;
}
React.memo & Key Prop
const UserCard = React.memo(({ user }) => {
return <div>{user.name}</div>;
});
function List({ items }) {
return (
<ul>
{items.map(item => (
<li key={item.id}>
{item.name}
</li>
))}
</ul>
);
}
Controlled vs Uncontrolled Components
function ControlledInput() {
const [value, setValue] = useState('');
return (
<input
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
}
function UncontrolledInput() {
const inputRef = useRef(null);
const handleSubmit = () => {
console.log(inputRef.current.value);
};
return (
<>
<input ref={inputRef} />
<button onClick={handleSubmit}>Submit</button>
</>
);
}
React Router v6
import { BrowserRouter, Routes, Route, Link, useNavigate, useParams } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/user/:id" element={<UserDetail />} />
</Routes>
</BrowserRouter>
);
}
function UserDetail() {
const { id } = useParams();
const navigate = useNavigate();
return (
<div>
<p>User ID: {id}</p>
<button onClick={() => navigate('/')}>Back</button>
</div>
);
}
Node.js & Express
Express Basics
const express = require('express');
const app = express();
app.use(express.json());
app.get('/api/users', (req, res) => {
res.json({ users: [] });
});
app.post('/api/users', (req, res) => {
const { name, email } = req.body;
res.status(201).json({ id: 1, name, email });
});
app.put('/api/users/:id', (req, res) => {
const { id } = req.params;
res.json({ id, updated: true });
});
app.delete('/api/users/:id', (req, res) => {
res.status(204).send();
});
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Internal Server Error' });
});
app.listen(3000, () => console.log('Server running'));
JWT Authentication
const jwt = require('jsonwebtoken');
const SECRET = 'your-secret-key';
const token = jwt.sign(
{ userId: 123, email: 'user@example.com' },
SECRET,
{ expiresIn: '24h' }
);
function authenticateToken(req, res, next) {
const token = req.headers['authorization']?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'No token' });
}
try {
const decoded = jwt.verify(token, SECRET);
req.user = decoded;
next();
} catch (err) {
res.status(403).json({ error: 'Invalid token' });
}
}
app.get('/api/protected', authenticateToken, (req, res) => {
res.json({ user: req.user });
});
REST API Status Codes
| Code |
Status |
When to Use |
| 200 |
OK |
Request successful, returning data |
| 201 |
Created |
Resource created successfully |
| 204 |
No Content |
Request successful, no response body (DELETE) |
| 400 |
Bad Request |
Invalid request data |
| 401 |
Unauthorized |
Authentication required/failed |
| 403 |
Forbidden |
Authenticated but no permission |
| 404 |
Not Found |
Resource doesn't exist |
| 409 |
Conflict |
Request conflicts (duplicate email) |
| 500 |
Server Error |
Unhandled server error |
Input Validation with Zod
const { z } = require('zod');
const userSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
age: z.number().int().positive().optional(),
});
app.post('/api/users', (req, res) => {
try {
const validated = userSchema.parse(req.body);
res.status(201).json(validated);
} catch (err) {
res.status(400).json({ errors: err.errors });
}
});
Databases for Web Developers
SQL Basics
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
INSERT INTO users (name, email) VALUES ('John', 'john@example.com');
SELECT * FROM users WHERE email = 'john@example.com';
UPDATE users SET name = 'Jane' WHERE id = 1;
DELETE FROM users WHERE id = 1;
SELECT u.name, p.title
FROM users u
INNER JOIN posts p ON u.id = p.user_id;
SELECT u.name, COUNT(p.id)
FROM users u
LEFT JOIN posts p ON u.id = p.user_id
GROUP BY u.id;
Prisma ORM
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
userId Int
user User @relation("fields: [userId]", "references: [id]")
}
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
const user = await prisma.user.create({
data: { email: 'john@example.com', name: 'John' },
});
const users = await prisma.user.findMany({
where: { email: 'john@example.com' },
include: { posts: true },
});
const updated = await prisma.user.update({
where: { id: 1 },
data: { name: 'Jane' },
});
const user = await prisma.user.upsert({
where: { email: 'john@example.com' },
update: { name: 'John Updated' },
create: { email: 'john@example.com', name: 'John' },
});
PostgreSQL Features
- JSONB Columns: Store JSON with indexing and querying
- UUID: uuid_generate_v4() for distributed IDs
- Full-text search: tsvector, tsquery with pg_trgm extension
- Transactions: BEGIN, COMMIT, ROLLBACK for atomic operations
- Indexes: CREATE INDEX on columns for faster queries
Redis for Caching
SET user:1:name "John" EX 3600
GET user:1:name
HSET user:1 name "John" email "john@example.com"
HGET user:1 name
HGETALL user:1
LPUSH notifications:1 "New message"
LRANGE notifications:1 0 10
ZADD leaderboard 100 "user1" 95 "user2"
ZRANGE leaderboard 0 10 WITHSCORES
N+1 Query Problem
const users = await prisma.user.findMany();
for (const user of users) {
const posts = await prisma.post.findMany({
where: { userId: user.id }
});
}
const users = await prisma.user.findMany({
include: { posts: true }
});
System Design for Web
Full-Stack Architecture
Client Layer (React/Next.js)
↓ HTTPS
API Gateway (Node.js/Express)
↓
Business Logic
↓
Database Layer (PostgreSQL)
↓
Cache Layer (Redis)
↓
File Storage (S3)
- Load Balancer (nginx, HAProxy)
- Multiple API instances
- Database replication (master-slave)
- Redis cluster
- CDN for static assets
Real-time Features
| Method |
Latency |
Server Load |
Complexity |
Use Case |
| Polling |
High (seconds) |
High |
Simple |
Updates every few seconds |
| Long Polling |
Medium |
Medium |
Medium |
Near-real-time updates |
| SSE |
Low |
Low-Medium |
Medium |
Server → Client updates |
| WebSockets |
Very Low |
Medium-High |
High |
Bidirectional real-time |
File Upload Architecture
1. Client requests upload permission from API
2. API generates presigned URL (15 min expiry)
3. Client uploads directly to S3 (no server involved)
4. S3 calls webhook to API (file processed)
5. API stores file metadata in database
- Server not bottleneck
- No large file in memory
- Secure: presigned URL expires
- Parallel uploads
Top 30 Interview Questions & Answers
1. What is the event loop in JavaScript?
▼
The event loop is a mechanism that allows JavaScript to handle asynchronous operations despite being single-threaded. It continuously checks the call stack and executes callbacks from the task queue when the stack is empty. Order: call stack → microtask queue (Promises) → macrotask queue (setTimeout). This is crucial for understanding async behavior in web apps.
2. Explain closures with a real example
▼
A closure is a function that has access to variables from its outer function's scope. Example: A makeCounter function returns an inner function that accesses the count variable. Each call creates a new closure with its own count variable. Used in data privacy, callbacks, and event handlers where you need to "remember" state.
3. What is the difference between == and ===?
▼
== is loose equality (type coercion): "5" == 5 is true. === is strict equality (no coercion): "5" === 5 is false. Always use === in production code to avoid subtle bugs. Type coercion can lead to unexpected behavior like 0 == false being true.
4. How does React reconciliation work?
▼
React uses a diffing algorithm (fiber architecture) to compare the new virtual DOM with the previous one. It identifies changed elements and updates only those in the real DOM. Key factors: component type (same?), keys in lists (stable identity), and props/state changes. This makes React efficient by minimizing DOM operations.
5. What is a Promise and how is it different from async/await?
▼
A Promise is an object representing an eventual outcome (fulfilled or rejected). async/await is syntactic sugar built on Promises, making async code look synchronous and easier to read. async function returns a Promise; await pauses execution until the Promise settles. Both enable handling asynchronous operations like API calls.
6. Explain CSS specificity calculation
▼
Specificity determines which CSS rule applies when there are conflicts. Inline styles (1000) > IDs (100) > classes/pseudo-classes (10) > elements (1). For example, .class (10) + element (1) = 11, which beats just element (1). !important overrides everything. Understanding specificity prevents unexpected styling.
7. What are React hooks and why were they introduced?
▼
Hooks are functions that let you use React features (state, effects) in functional components. Introduced in React 16.8 to replace class components which were verbose and had complex lifecycle management. Common hooks: useState (state), useEffect (side effects), useContext (context), useReducer (complex state), useMemo (optimization). They enable code reuse through custom hooks.
8. How does JWT authentication work?
▼
JWT (JSON Web Token) has three parts: header (algorithm), payload (user data), signature (server secret). Flow: (1) Client sends credentials, (2) Server creates JWT and returns it, (3) Client includes JWT in Authorization header for future requests, (4) Server verifies signature with secret key. Stateless - server doesn't store session info. Tokens expire (exp claim) for security.
9. What is CORS and how do you fix it?
▼
CORS (Cross-Origin Resource Sharing) is a browser security feature preventing cross-origin requests by default. To fix: (1) Add cors middleware to Express: app.use(cors()), (2) Set headers: Access-Control-Allow-Origin, Access-Control-Allow-Methods, (3) Handle preflight OPTIONS requests. CORS protects users from malicious sites stealing data.
10. Explain the CSS box model
▼
The box model describes how space is allocated around elements: content (actual size) → padding (inside space) → border (outline) → margin (outside space). Total width = content width + padding + border + margin. box-sizing: border-box makes width include padding/border. Understanding this prevents layout surprises.
11. What is the difference between null and undefined?
▼
null is an intentional absence of value (assigned by programmer). undefined is unintentional - variables not initialized, functions with no return, missing function parameters. typeof null is "object" (historical bug), typeof undefined is "undefined". Both are falsy in conditionals but === null checks specifically.
12. How does prototypal inheritance work?
▼
Objects inherit from other objects via the prototype chain. When accessing a property, JavaScript looks in the object, then its prototype, then the prototype's prototype, etc. Constructor functions (function Animal() {}) have a prototype property where methods are stored. To set up inheritance: ChildConstructor.prototype = Object.create(ParentConstructor.prototype). Modern approach uses class syntax which is syntactic sugar.
13. What is memoization in React and when should you use it?
▼
Memoization caches results to avoid recalculation. React.memo prevents component re-render if props unchanged. useMemo caches computed values. useCallback caches function references. Use when: (1) expensive calculations, (2) passing functions to memoized children, (3) preventing infinite loops. Overuse hurts performance - only optimize proven bottlenecks.
14. Explain REST principles
▼
REST (Representational State Transfer) uses HTTP methods for CRUD: GET (read), POST (create), PUT (full update), PATCH (partial update), DELETE (remove). Resources are identified by URLs (/users, /users/123). Stateless - each request is independent. Responses use standard status codes (200, 201, 400, 404, 500). Makes APIs predictable and cacheable.
15. What is the virtual DOM?
▼
The virtual DOM is an in-memory representation of the real DOM. When state changes, React creates a new virtual DOM, diffs it against the old one, and updates only the changed parts in the real DOM. This batching improves performance since DOM updates are expensive. Helps React provide a declarative API - you describe what the UI should be, React handles updates.
16. What are HTTP status codes and when do you use them?
▼
1xx (informational), 2xx (success: 200 OK, 201 Created, 204 No Content), 3xx (redirect), 4xx (client error: 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found), 5xx (server error: 500, 503 Service Unavailable). Choose appropriate status to communicate request outcome to client. Proper status codes improve debugging and API usability.
17. How do you handle errors in Express?
▼
Use a dedicated error-handling middleware with 4 parameters (err, req, res, next). Must be defined after all other app.use() and route handlers. Catches errors thrown or passed to next(err). Should log errors, set appropriate status code, and send error response to client. Also wrap async/await in try-catch in route handlers.
18. What is the N+1 query problem?
▼
When fetching a list of items, then for each item fetching related data in a loop. Example: fetch 100 users, then for each user fetch their posts = 101 queries instead of 1. Solution: Use JOINs in SQL or eager loading in ORMs (include: { posts: true } in Prisma). Causes major performance issues at scale.
19. How does XSS attack work and how do you prevent it?
▼
XSS (Cross-Site Scripting) injects malicious JavaScript into web pages. Example: User submits "<img src=x onerror='stealCookie()'>" and it gets stored/displayed. Prevention: (1) Always escape user input in output, (2) Use frameworks that auto-escape (React escapes by default), (3) Content-Security-Policy header restricts script sources, (4) Never use dangerouslySetInnerHTML with user input, (5) Input validation.
20. What is middleware in Express?
▼
Middleware functions process requests and responses. Have access to request object (req), response object (res), and next function. Execute in order they're defined. Can modify requests/responses, end response, or call next() to pass control to next middleware. Examples: express.json() (parse JSON), cors() (handle CORS), authentication (verify tokens), error handling.
21. Explain controlled components in React
▼
Controlled component: React state controls the input value. You set value={state} and update it with onChange handler. Gives React full control - can validate, format, or restrict input. Uncontrolled: DOM controls value, use ref to access it. Controlled is recommended - easier to validate and sync with other form elements.
22. What is hoisting in JavaScript?
▼
JavaScript hoisting moves declarations to top of scope. var declarations are hoisted and initialized to undefined. let/const are hoisted but not initialized (Temporal Dead Zone - accessing throws ReferenceError). Function declarations are fully hoisted. This explains why var x; console.log(x); outputs undefined rather than error. Use const by default to avoid hoisting confusion.
23. How do you optimize React performance?
▼
(1) Code splitting with React.lazy and Suspense, (2) Memoization: React.memo, useMemo, useCallback for expensive operations, (3) Key prop in lists (use unique IDs, not index), (4) useReducer instead of multiple useState for related state, (5) Avoid inline objects/functions as props, (6) Use production builds, (7) Profiler API to identify bottlenecks, (8) Measure with Lighthouse.
24. What is the purpose of useRef in React?
▼
useRef returns a mutable object that persists across re-renders. Use for: (1) Accessing DOM directly (focus input, measure size), (2) Storing mutable value that doesn't trigger re-render (timer IDs, previous props), (3) Storing state you don't need in UI. Ref changes don't re-render. Don't overuse - prefer state for values that affect UI.
25. Explain the difference between SQL and NoSQL
▼
SQL (PostgreSQL): Structured schema, ACID transactions, relations/JOINs, scales vertically. Best for structured data with relationships. NoSQL (MongoDB): Schema-less/flexible, eventual consistency, documents/collections, scales horizontally. Best for unstructured data, high write volume. Choose SQL for financial systems (need ACID); NoSQL for real-time analytics (high throughput). Can use both (polyglot persistence).
26. What is a database index and when should you use it?
▼
Index creates fast lookup for columns (like a book's index). Without index, database scans all rows (O(n)). With index, lookup is O(log n). Index trades space for speed. Index on columns you filter/sort (WHERE, ORDER BY). Avoid indexes on low-cardinality columns (gender: M/F) or columns you rarely query. Monitor: indexes slow down writes and use disk space.
27. How do you implement authentication in a web app?
▼
(1) User submits credentials (email/password), (2) Server hashes password with bcrypt and compares with stored hash, (3) If match, generate JWT or session token, (4) Return token to client, (5) Client includes token in Authorization header for future requests, (6) Server validates token before processing request. Use HTTPS to protect credentials in transit. Never store passwords in plain text.
28. What is the difference between let and const?
▼
Both let and const are block-scoped (unlike var which is function-scoped). const cannot be reassigned after initialization. Both are hoisted but not initialized (Temporal Dead Zone). Use const by default (prevents accidental reassignment), let when you need to reassign. const for objects/arrays doesn't mean immutable - properties can change, just can't reassign the reference.
29. Explain Flexbox vs CSS Grid
▼
Flexbox: 1D layout (row or column), content-first, distributes space around items. Best for navigation bars, button groups, alignment. CSS Grid: 2D layout (rows and columns), design-first, explicit grid areas. Best for page layouts, complex designs. Can use both together - Grid for overall layout, Flexbox for components within grid cells.
30. What is GraphQL and how does it differ from REST?
▼
GraphQL: query language for APIs. Client specifies exactly what data it needs (no over/under fetching). Single endpoint. Strongly typed schema. Complex queries with relationships in one request. REST: multiple endpoints (GET /users, GET /users/1/posts), inflexible data (over/under fetching), simpler to cache. GraphQL better for complex data requirements; REST simpler for simple CRUD APIs. GraphQL has steeper learning curve.
Glossary
API (Application Programming Interface)
Contract for how software components communicate. REST API uses HTTP for web services.
CORS (Cross-Origin Resource Sharing)
Browser security mechanism allowing/restricting requests between different origins (domains).
JWT (JSON Web Token)
Stateless authentication token with header.payload.signature structure, verified using server secret.
Virtual DOM
In-memory copy of real DOM used by React to efficiently detect and apply changes.
Hoisting
JavaScript behavior where var/function declarations move to top of scope during compilation.
Closure
Function retaining access to outer function's variables even after outer function completes.
Promise
Object representing eventual completion or failure of async operation, with then/catch methods.
ORM (Object-Relational Mapping)
Tool (Prisma, Mongoose) translating database records to objects, providing type-safe queries.
N+1 Query Problem
Performance issue where fetching list triggers N additional queries for related data (1 + N total).
XSS (Cross-Site Scripting)
Security vulnerability where attacker injects malicious JavaScript into web pages.
CSRF (Cross-Site Request Forgery)
Attack where authenticated user unknowingly makes request to another site, prevented by tokens.
Memoization
Caching technique storing computation results to avoid recalculation with same inputs.
Middleware
Function in Express that processes request/response, can modify them or call next handler.
REST (Representational State Transfer)
API architectural style using HTTP methods (GET, POST, PUT, DELETE) for CRUD operations.
React Hook
Function allowing functional components to use state and side effects (useState, useEffect, etc).