Development
Frontend Developer
A complete guide covering JavaScript Core, Asynchronous JS, React Fundamentals & Advanced, Next.js (App Router), TypeScript, Performance Optimization, and Web Security.
What you will be asked about
How to prepare
- Go through the topic list above and mark every one you cannot explain for five minutes unprepared. Those are your gaps.
- Pair every concept with a story from your own work — interviewers probe depth, and depth comes from having actually done it.
- Do the DSA rounds anyway. Almost every role in this list still screens with coding.
- Prepare two projects you can whiteboard end to end, including what you would change now.
Also do
Frontend Developer interview questions210
JavaScript Core20
var: Function-scoped, can be redeclared, and is hoisted with a value of `undefined`. let: Block-scoped, cannot be redeclared in the same scope, and is hoisted but stays in the 'Temporal Dead Zone' until initialized. const: Same as let, but must be initialized immediately and its reference cannot be reassigned.
A closure is a function that remembers its outer variables even after the outer function has finished executing. Real-world example: A counter function. The inner function increments a variable defined in the parent function's scope, protecting that variable from global access while keeping it persistent.
The Event Loop is a mechanism that allows JavaScript to perform non-blocking I/O operations despite being single-threaded. It constantly checks the Call Stack; if it's empty, it takes tasks from the Callback Queue or Microtask Queue and pushes them onto the stack.
== (Loose Equality): Performs type coercion, meaning it converts the operands to a common type before comparing (e.g., `5 == '5'` is true). === (Strict Equality): Compares both the value and the type without coercion (e.g., `5 === '5'` is false).
The value of `this` depends on how a function is called: 1) Global context: Window (or undefined in strict mode). 2) Object method: The object itself. 3) Constructor/Class: The new instance created. 4) Arrow functions: Lexical `this` (inherits from parent scope). 5) Event handlers: The element that received the event.
All three change the context of `this`. call: Invokes the function immediately with arguments passed individually. apply: Invokes the function immediately with arguments passed as an array. bind: Returns a *new* function with a bound context to be called later.
Hoisting is JavaScript's default behavior of moving declarations to the top of the current scope. Variable declarations (`var`) are hoisted and initialized as `undefined`. Function declarations are fully hoisted. `let` and `const` are hoisted but not initialized, resulting in a ReferenceError if accessed early.
In JS, every object has a hidden property called `[[Prototype]]` that points to another object. When you access a property that doesn't exist on an object, JS looks for it on the prototype, then the prototype's prototype, forming a 'Prototype Chain'.
undefined: A variable has been declared but not yet assigned a value (automatic). null: An assignment value representing the intentional absence of any object value (manual). `typeof undefined` is 'undefined', while `typeof null` is 'object'.
Arrow functions provide a shorter syntax and: 1) Do not have their own `this` (lexical binding). 2) Do not have `arguments` object. 3) Cannot be used as constructors (cannot use `new`). 4) Don't have a `prototype` property.
Synchronous: Code executes line by line; each line must finish before the next one starts (blocking). Asynchronous: Code allows the program to initiate a task and move to the next one before the first task finishes (non-blocking), using callbacks, promises, or async/await.
Shallow Copy: Copies the top-level object but nested objects still share the same reference (e.g., `Object.assign` or spread operator). Deep Copy: Copies all levels, creating entirely new references for nested objects (e.g., `JSON.parse(JSON.stringify(obj))` or `structuredClone()`).
Spread (...): Expands an iterable (like an array) into individual elements (e.g., `[...arr]`). Rest (...): Collects multiple individual arguments into a single array inside a function definition (e.g., `function(a, ...others) {}`).
Destructuring is a syntax that allows you to unpack values from arrays or properties from objects into distinct variables. Example: `const { name, age } = user;` or `const [first, second] = array;`.
Event Bubbling: The event starts from the target element and 'bubbles' up to the root (default). Event Capturing (Trickling): The event starts from the root and goes down to the target element. You can choose capturing by passing `{ capture: true }` to `addEventListener`.
Event delegation is a pattern where you attach a single event listener to a parent element instead of multiple listeners to children. It works because of event bubbling. Useful for: Better performance (fewer listeners) and handling dynamically added child elements.
forEach: Executes a function for each element (returns undefined). map: Creates a *new* array by transforming every element. filter: Creates a *new* array with elements that pass a test. reduce: Reduces the array to a single value (e.g., a sum or object).
Template literals use backticks (``) instead of quotes. They allow: 1) Multi-line strings. 2) String interpolation using `${variable}` syntax. 3) Tagged templates for advanced string processing.
slice(start, end): Returns a portion of an array as a *new* array; it does not modify the original array. splice(start, count, items): Changes the original array by removing or replacing existing elements and/or adding new ones.
A Promise is an object representing the eventual completion (or failure) of an asynchronous operation. It has three states: Pending (initial), Fulfilled (successful), and Rejected (failed).
Asynchronous JavaScript10
Promises use `.then()` and `.catch()` chains to handle results. async/await is syntactic sugar built on top of promises that allows you to write asynchronous code that looks and behaves like synchronous code, making it more readable and easier to debug.
Callback hell occurs when multiple nested callbacks make code hard to read and maintain (the 'Pyramid of Doom'). It can be avoided by: 1) Using Promises, 2) Using async/await, or 3) Modularizing code into smaller, named functions.
Microtasks (Promises, `queueMicrotask`) have higher priority and execute immediately after the current script and before the next macrotask. Macrotasks (`setTimeout`, `setInterval`, I/O) are handled by the event loop in the next iteration.
Errors in async/await are handled using `try...catch` blocks. If an awaited promise rejects, the error is thrown into the `catch` block. Alternatively, you can chain a `.catch()` directly onto the awaited function call.
`Promise.all()` takes an array of promises and returns a single promise that resolves when all input promises resolve, or rejects if any one of them fails. Use it when you need to perform multiple concurrent operations (like fetching data from three different APIs) and wait for all to finish.
all: Waits for all to succeed or one to fail. race: Returns the first promise to settle (either success or fail). allSettled: Waits for all to finish, regardless of success/failure. any: Returns the first successful promise, ignoring failures until it runs out of options.
Generators are functions that can be exited and later re-entered. They are defined with `function*` and use the `yield` keyword to pause execution and return a value. They are useful for creating iterators or handling complex async flows.
The Fetch API is a modern interface for making network requests. It returns a Promise that resolves to the `Response` object. Unlike `XMLHttpRequest`, it won't reject on HTTP error status (like 404); it only rejects on network failure.
A fetch request is cancelled using the AbortController interface. You create a controller, pass its signal to the fetch options, and call `controller.abort()` when you want to terminate the request.
setTimeout: Executes a function once after a specified delay. setInterval: Repeatedly executes a function with a fixed time delay between each call. `setInterval` can lead to task 'stacking' if the task takes longer than the interval.
React Fundamentals20
React is an open-source JavaScript library for building user interfaces, primarily for single-page applications. It is used because it allows developers to create reusable UI components and manage state efficiently using a virtual DOM.
JSX (JavaScript XML) is a syntax extension that allows you to write HTML-like code inside JavaScript. Browsers cannot read JSX directly, so tools like Babel transform it into standard `React.createElement()` calls.
The Virtual DOM is a lightweight copy of the real DOM kept in memory. When state changes, React updates the Virtual DOM first, compares it with the previous version (diffing), and then only updates the necessary parts in the real DOM (reconciliation).
Props are read-only and passed from parent to child (external). State is an internal data store managed within the component itself (internal) and can be changed by the component to trigger re-renders.
Hooks are functions that let you 'hook into' React state and lifecycle features from functional components. They were introduced to solve the complexity of class components, allow logic reuse without HOCs, and improve code readability.
`useState` is a hook that allows you to add state to a functional component. It returns an array with two elements: the current state value and a function to update it. Updating the state triggers a re-render.
`useEffect` allows you to perform side effects (data fetching, subscriptions, manual DOM changes). It runs after every render by default, but you can control it using a dependency array: `[]` for once, or `[data]` for specific changes.
`useEffect` runs asynchronously after the browser has painted the screen. `useLayoutEffect` runs synchronously before the paint. Use `useLayoutEffect` only when you need to measure DOM or prevent visual flickers.
`useRef` returns a mutable ref object whose `.current` property persists for the full lifetime of the component. Use it for: 1) Accessing DOM elements directly, 2) Storing values that don't trigger re-renders when changed.
`useContext` provides a way to share data (like themes or auth) across the entire component tree without passing props manually at every level (prop drilling). It consumes a Context object created by `React.createContext()`.
`useMemo` is a hook that memoizes the result of a calculation between re-renders. Use it when you have an expensive computation that shouldn't run on every render unless its specific dependencies change.
`useCallback` memoizes the function definition itself. It is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary re-renders (like those wrapped in `React.memo`).
`useReducer` is a hook for managing complex state logic that involves multiple sub-values or when the next state depends on the previous one. Use it over `useState` for deep state updates or to keep state logic separate from the component UI.
Reconciliation is the process by which React updates the DOM. The diffing algorithm compares the new Virtual DOM with the previous one. It assumes that two elements of different types will produce different trees and uses 'keys' to identify which child elements are stable across renders.
Controlled: The component's input value is driven by React state (using `value` and `onChange`). Uncontrolled: The form data is handled by the DOM itself; you use `refs` to pull the values when needed.
An HOC is a pattern where a function takes a component and returns a new component with added functionality (e.g., `withAuth(MyComponent)`). It is a way to reuse component logic.
Render Props is a technique for sharing code between React components using a prop whose value is a function. The component calls this function to know what to render, passing along data as arguments.
Compound components are a pattern where multiple components work together to form a unit with shared implicit state (e.g., `<Tabs>` and `<Tab>`). They usually communicate via the Context API to avoid manual prop drilling.
Portals allow you to render a child component into a DOM node that exists outside the hierarchy of the parent component. Common use cases include Modals, Tooltips, and Dropdowns to avoid CSS overflow/z-index issues.
Error Boundaries are class components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed.
React Advanced20
`React.memo` is a higher-order component that memoizes a component, preventing it from re-rendering if its props haven't changed. Use it for pure functional components that render often with the same props.
React.memo: Wraps a component to prevent re-renders. useMemo: Memoizes a computed value. useCallback: Memoizes a function instance.
Suspense lets components 'wait' for something (like code loading or data fetching) before rendering. It allows you to declaratively specify a loading UI (fallback) while children are being prepared.
Server Components are a new type of component that render exclusively on the server. They allow for zero-bundle-size components, direct database access, and improved performance by reducing the amount of JS sent to the client.
Concurrent Mode is a set of features that help React apps stay responsive by adjusting to the user’s device capabilities and network speed. It allows React to interrupt a long-running render to handle a high-priority event like a user click.
Code splitting is a technique that breaks your bundle into smaller chunks that can be loaded on demand. In React, this is achieved using `React.lazy()` and `Suspense` to load components only when they are needed.
Context API is a way to pass data through the component tree without prop drilling. Use it for 'global' data like current user, theme, or preferred language.
Prop drilling is passing props through multiple levels of components that don't need the data themselves. Avoid it using Context API, Composition, or state management libraries like Zustand.
The `key` prop helps React identify which items have changed, been added, or removed in a list. It provides stability to the Virtual DOM diffing process to ensure correct state and performance.
Using `index` as a key can lead to issues with component state and UI glitches if the list items are reordered, filtered, or deleted, as React might reuse the wrong component instance.
Hydration is the process where React attaches event listeners to the static HTML sent from the server, making the page interactive on the client side. It 'breathes life' into the pre-rendered HTML by matching it with the client-side Virtual DOM.
Custom hooks are JavaScript functions whose names start with 'use' and that can call other hooks. They allow you to extract component logic into reusable functions. You create them by moving stateful logic (like a fetcher or window-sizer) into a separate function and returning the necessary data/functions.
`useImperativeHandle` customizes the instance value that is exposed to parent components when using `ref`. It should be used with `forwardRef` to allow a parent to call specific functions inside a child component while keeping the rest of the child's state private.
`useDebugValue` is used to display a label for custom hooks in React DevTools. It is mainly used in library development to provide a better debugging experience for developers using those custom hooks.
`useTransition` allows you to mark state updates as 'transitions' which are non-urgent. This lets React keep the UI responsive (e.g., an input field) while a heavy UI update (e.g., filtering a large list) happens in the background.
`useDeferredValue` lets you defer re-rendering a non-urgent part of the tree. It is similar to debouncing or throttling but handled natively by React to ensure that the UI stays snappy during expensive renders.
`useId` is a hook for generating unique IDs that are stable across the server and client. It is primarily used for accessibility attributes (like `aria-describedby`) to ensure there are no ID mismatches during hydration.
Automatic Batching is when React groups multiple state updates into a single re-render for better performance. In React 18, this happens automatically even inside promises, setTimeouts, and native event handlers.
1) Use `React.memo`, `useMemo`, and `useCallback`. 2) Implement windowing/virtualization for long lists. 3) Code-split with `React.lazy`. 4) Avoid anonymous functions in props. 5) Use the Production build for deployment.
Common causes include: 1) Updating state with the same value. 2) Passing new object/function references as props. 3) Parent components re-rendering. 4) Context value changes affecting all consumers.
Performance20
Debouncing ensures a function is only called after a certain amount of time has passed since the last time it was invoked. Implementation involves a `setTimeout` that is cleared and reset on every call until the user stops the action (like typing).
Throttling limits the execution of a function to once every X milliseconds. While Debouncing waits for a pause, Throttling ensures periodic execution during a continuous action (like scrolling).
Lazy loading is the practice of delaying the initialization of a resource until it is needed. Use it for images below the fold, large components (like charts), and routes that aren't part of the critical initial view.
Code splitting breaks a large bundle into smaller chunks. In React, it's implemented using `import()` dynamic syntax combined with `React.lazy()` and `Suspense` to load specific parts of the app on demand.
Tree shaking is a step in the build process (by Webpack/Vite) that removes unused code from the final bundle. It relies on the static structure of ES Modules (`import`/`export`) to determine what code is dead.
LCP (Largest Contentful Paint): Measures loading speed. FID (First Input Delay): Measures interactivity. CLS (Cumulative Layout Shift): Measures visual stability. Google uses these to rank user experience.
1) Use modern formats (WebP/AVIF). 2) Use responsive images (`srcset`). 3) Implement lazy loading (`loading='lazy'`). 4) Compress images using tools like Sharp or TinyPNG. 5) Use a CDN for image delivery.
Critical CSS is the CSS required to render the 'above the fold' content. It is extracted and inlined into the HTML `<head>` for near-instant rendering, while the rest of the CSS is loaded asynchronously.
Preload: High-priority fetch for current page. Prefetch: Low-priority fetch for future navigation. Preconnect: Establishes early connection (DNS/TLS) to a third-party domain (like Google Fonts).
Memoization is an optimization technique where you store the results of expensive function calls and return the cached result when the same inputs occur again. It trades memory for speed.
The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or the viewport. Common use cases include lazy-loading images, implementing infinite scroll, and triggering animations as elements enter the view.
Infinite scroll is usually implemented by detecting when the user has scrolled to the bottom of the page (using the Intersection Observer API or scroll event listeners) and then fetching the next 'page' of data from an API and appending it to the existing list.
Virtual scrolling is a technique where only the items currently visible in the viewport are rendered in the DOM, even if the list contains thousands of items. As the user scrolls, items entering the view are added and items leaving the view are removed. Libraries like `react-window` or `react-virtualized` are commonly used for this.
Browser caching allows the browser to store static assets locally. You leverage it by setting HTTP headers like `Cache-Control: max-age=...` or using `ETags`. This avoids unnecessary network requests on subsequent visits, significantly improving load times.
A Content Delivery Network (CDN) is a distributed network of servers that caches content geographically closer to users. It improves performance by reducing latency (the physical distance data travels) and offloading traffic from the origin server.
Bundle size optimization involves reducing the total size of JavaScript files sent to the client. Techniques include Tree Shaking, using lighter alternatives to heavy libraries (e.g., Day.js instead of Moment.js), and Code Splitting to load only what's necessary for the current route.
CSR (Client-Side Rendering): Browser downloads a minimal HTML file and JS, then JS builds the page (fast transitions, slow initial load). SSR (Server-Side Rendering): Server generates the full HTML on every request (fast initial load, better SEO, higher server load).
A PWA is a type of application software delivered through the web, built using common web technologies. It provides a native app-like experience, including offline support, push notifications, and the ability to be 'installed' on the home screen.
A Service Worker is a script that the browser runs in the background, separate from a web page. It acts as a proxy between the web app and the network, enabling features like offline caching, background sync, and push notifications.
Web Workers are used for heavy computations to keep the UI thread responsive. Service Workers are used to handle network requests, push notifications, and offline support, acting as a network proxy.
State Management15
Redux is a pattern and library for managing and updating global application state. You should use it when you have a large-scale application with complex state logic that needs to be accessed by many deeply nested components.
Redux Toolkit (RTK) is the official, opinionated toolset for efficient Redux development. It simplifies Redux by providing functions like `createSlice` (reducing boilerplate) and `createAsyncThunk` (for handling async logic).
Context API is built into React and is best for low-frequency updates (e.g., Theme, Locale). Redux is an external library optimized for high-frequency updates and comes with powerful debugging tools like Redux DevTools.
Zustand is a small, fast, and scalable bearbones state-management solution. Unlike Redux, it doesn't require providers or complex boilerplate; it uses a simpler hook-based API and doesn't wrap the entire app in a 'Provider' by default.
Recoil is a state management library for React created by Meta. It uses 'Atoms' (units of state) and 'Selectors' (pure functions to derive state), allowing for fine-grained updates and better performance in complex UIs.
Jotai is an atomic state management library for React, similar to Recoil but with a smaller footprint and a focus on simplicity. It allows you to build state by combining small 'atoms' of data.
MobX is a state management library based on Observables. It uses transparent functional reactive programming to automatically track state changes and update the UI accordingly, focusing on a more 'OO' (Object Oriented) style than Redux.
Flux is an architecture pattern for managing data flow in UIs. It enforces a unidirectional data flow: Action -> Dispatcher -> Store -> View. Redux is a popular implementation of this pattern.
Local State: Managed within a single component (e.g., `useState`). Global State: Managed outside the component tree and accessible by multiple components (e.g., Redux, Zustand, Context).
Middleware provides a way to interact with actions that have been dispatched before they reach the reducer. Thunk allows you to write action creators that return a function (for simple async). Saga uses Generators to handle complex async side effects in a more testable way.
Redux Thunk is a middleware that allows you to write action creators that return a function instead of an action; it's simple and great for basic async logic. Redux Saga uses ES6 Generators to make asynchronous flows easier to read, write, and test; it is better suited for complex side effects and long-running background tasks.
Immer is a library that allows you to work with immutable state by writing 'mutative' code. It creates a temporary 'draft' of the state; any changes you make to the draft are recorded and applied to produce the next immutable state, eliminating the need for complex object spreading.
Redux Persist is a library used to save the Redux store in local storage or session storage. This ensures that the application state remains intact even after the user refreshes the page or reopens the browser.
React Query (TanStack Query) is a library for fetching, caching, and synchronizing asynchronous data in React. Use it to manage server state (API data), as it handles caching, background updates, and stale data out of the box, reducing the need for manual `useEffect` logic.
SWR is a React Hooks library for remote data fetching developed by Vercel. It follows the stale-while-revalidate strategy: first return data from cache (stale), then send the fetch request (revalidate), and finally come up with the up-to-date data.
SSR, CSR, SSG15
CSR (Client-Side Rendering): Content is rendered in the browser (fast navigation, poor SEO). SSR (Server-Side Rendering): HTML is generated on the server for *every* request (best for dynamic SEO data). SSG (Static Site Generation): HTML is generated at *build time* (fastest performance, best for blogs/docs).
Next.js is a React framework that provides a suite of features like SSR, SSG, ISR, and automatic code splitting. It solves problems related to SEO in React apps, improves initial load performance, and simplifies routing and API development within a single project.
`getStaticProps` is used for Static Site Generation. It fetches data at build time, allowing the page to be pre-rendered as a static HTML file. This results in extremely fast page loads as the data is already prepared before the user requests it.
`getServerSideProps` is used for Server-Side Rendering. It runs on the server for every single incoming request, making it ideal for pages that display frequently updated data or user-specific content that cannot be cached.
`getStaticPaths` is used in dynamic routes (e.g., `[id].js`) alongside `getStaticProps`. It defines the list of paths that should be pre-rendered to static HTML at build time.
ISR allows you to update static pages *after* the site has been built. By setting a `revalidate` time in `getStaticProps`, Next.js will rebuild the page in the background once that time expires, providing the speed of SSG with the freshness of SSR.
The App Router is a new file-system based router built on React Server Components. It supports shared layouts, nested routing, loading states, and error handling, while offering significantly improved performance by minimizing the JS sent to the client.
Remix is a web framework focused on web standards and HTTP caching. Unlike Next.js which focuses on SSG, Remix relies heavily on SSR and the 'Loader/Action' pattern to handle data, emphasizing 'no-JS' functionality and fast transitions.
Astro is a framework designed for content-rich websites. Its Islands Architecture sends zero JavaScript to the client by default, only 'hydrating' specific interactive components (islands) while keeping the rest of the page as static HTML.
A hydration mismatch occurs when the HTML pre-rendered on the server does not exactly match what the client-side React code expects to render initially. This often happens due to date formatting, random numbers, or checking `window` during the first render.
1) Better SEO: Search engines can easily crawl the full HTML. 2) Faster FCP: Users see content immediately without waiting for large JS bundles to execute. 3) Social Sharing: Metadata is correctly populated for social media previews.
1) High TTFB: The server must generate the page on every request. 2) Complexity: Managing server-side vs client-side code (hydration). 3) Server Load: Scaling is more expensive compared to serving static files from a CDN.
Edge Runtime is a lightweight execution environment that runs your code at the CDN 'edge' (closer to the user). It has faster startup times than standard Node.js but supports a limited set of APIs, making it ideal for middleware and geo-specific logic.
Streaming SSR allows the server to send the HTML to the browser in chunks as they are generated, rather than waiting for the entire page to be ready. This significantly improves perceived performance as the browser can start rendering parts of the page earlier.
Partial Hydration is a technique where only certain parts of a page are made interactive (hydrated) with JavaScript, while the rest remains static HTML. This reduces the amount of JavaScript that needs to be downloaded and executed on the client.
TypeScript15
TypeScript is a strongly typed superset of JavaScript that compiles to plain JavaScript. It is used to catch errors during development (compile-time) rather than at runtime, provide better tooling/autocomplete (IntelliSense), and make large codebases easier to maintain and refactor.
Interfaces are better for defining object shapes and support 'declaration merging' (adding properties to the same interface name). Types are more flexible and can define unions, primitives, and tuples. Generally, use `interface` for objects and `type` for complex logic or unions.
Generics allow you to create reusable components that work with a variety of types rather than a single one. They act as 'type variables' (e.g., `<T>`) that capture the type provided by the user, ensuring type safety without losing flexibility.
Partial<T>: Makes all properties optional. Pick<T, K>: Creates a type by selecting specific keys from T. Omit<T, K>: Creates a type by removing specific keys from T. Record<K, T>: Constructs an object type with keys K and values T.
Type inference is TypeScript's ability to automatically figure out the type of a variable based on its assigned value. For example, if you write `let x = 5;`, TypeScript automatically infers that `x` is of type `number` without you needing to explicitly declare it.
any: Completely bypasses type checking (unsafe). unknown: A type-safe counterpart to `any`. You can assign anything to `unknown`, but you cannot perform operations on it until you narrow the type using type guards or assertions.
Type assertion is a way to tell the compiler 'trust me, I know what I'm doing.' It is used when you know more about the value's type than TypeScript does (e.g., `const input = document.getElementById('myInput') as HTMLInputElement;`).
Union (|): A value that can be one of several types (e.g., `string | number`). Intersection (&): Combines multiple types into one, requiring the value to satisfy all combined types.
The `never` type represents values that never occur. It is used for function return types that always throw an exception, functions with infinite loops, or to handle exhaustive checks in switch statements for union types.
Conditional types allow you to select one of two possible types based on a condition expressed as a type relationship test (e.g., `T extends U ? X : Y`). They behave like ternary operators for types.
Mapped types allow you to create new types based on the properties of an existing type. For example, you can create a new type where all properties of an interface are made `readonly` or `boolean` using the `keyof` operator.
The `readonly` modifier makes a property immutable after its initial assignment. It can be used for class properties, interface properties, or as a utility type `Readonly<T>` for entire objects and arrays.
Enums allow you to define a set of named constants. Numeric enums (default) start from 0 and increment, while string enums allow for more readable values in logs and debugging.
Type Guard: A runtime check (like `typeof` or `instanceof`) that narrows the type within a block. Type Assertion: A compile-time override (`as string`) that tells the compiler to treat a value as a specific type without any actual runtime check.
The `keyof` operator takes an object type and produces a string or numeric literal union of its keys. For example, if `interface User { id: number; name: string; }`, then `keyof User` is `'id' | 'name'`.
Web APIs20
localStorage: Stores data with no expiration date; data persists even after the browser is closed. sessionStorage: Stores data for the duration of the page session; data is cleared when the tab or window is closed.
Storage (Local/Session): Larger capacity (5-10MB), strictly client-side. Cookies: Smaller (4KB), sent to the server with every request, used for authentication and tracking.
The Fetch API provides a modern, Promise-based interface for fetching resources across the network. It is the replacement for the older `XMLHttpRequest` and handles requests and responses in a much cleaner way.
XHR: Older, callback-based, handles progress events more easily. Fetch: Promise-based, cleaner syntax, doesn't reject on 404/500 errors (only network failure), and uses the `Body` mixin for parsing JSON.
CORS (Cross-Origin Resource Sharing) is a security feature that restricts web pages from making requests to a different domain than the one that served the page. It is handled on the server by setting `Access-Control-Allow-Origin` headers.
The History API provides access to the browser's session history. It allows you to manipulate the address bar URL without a full page refresh using `pushState()` and `replaceState()`, which is the foundation of client-side routing in frameworks like React Router.
The Geolocation API allows the user to provide their location to web applications. It provides the latitude and longitude of the device via the `navigator.geolocation` object, subject to user permission.
The Notification API allows web pages to display system-level notifications to the user, even if the browser is in the background. It is often used in conjunction with Service Workers for push messaging.
The File API provides a way for web applications to access and read the contents of files stored on the user's computer (usually via `<input type='file'>` or drag-and-drop), using objects like `File`, `FileList`, and `FileReader`.
IndexedDB is a low-level API for client-side storage of large amounts of structured data, including files/blobs. It is a transactional, key-value based NoSQL database that is much more powerful than `localStorage`.
The Cache API allows browsers to store pairs of HTTP requests and responses. It is a key component of Service Workers, enabling 'Offline-First' applications by allowing developers to serve content directly from the cache when the network is unavailable.
The Broadcast Channel API allows simple communication between different browser contexts (tabs, windows, or iframes) of the same origin. It enables a message sent from one tab to be received by all other open tabs of the same site.
The Page Visibility API lets you know when a user leaves the page or returns to it. You can use the `visibilitychange` event to pause heavy animations or stop polling an API when the tab is hidden to save resources.
This API provides information about the system's connection, such as the effective connection type (4g, 3g, etc.). It allows developers to serve high-quality images to fast connections and lower-quality versions to slow ones.
The Clipboard API provides the ability to respond to clipboard commands (cut, copy, and paste) and to asynchronously read from and write to the system clipboard using `navigator.clipboard`.
WebSockets provide a full-duplex, persistent communication channel over a single TCP connection. Use it for real-time applications where low latency is critical, such as chat apps, live sports updates, or collaborative editing tools.
HTTP: Unidirectional (client asks, server answers), stateless, and closes after the response. WebSockets: Bidirectional (either can send at any time), stateful, and the connection stays open until explicitly closed.
SSE is a standard allowing servers to push data to web pages over HTTP. Unlike WebSockets, it is unidirectional (server-to-client only), but it is simpler to implement and handles reconnection automatically.
WebRTC (Web Real-Time Communication) is an open-source project that enables peer-to-peer communication (audio, video, and data) directly between browsers without needing an intermediate server for the media stream.
This API enables HTML elements to be draggable and allows you to define 'drop zones'. It uses events like `dragstart`, `dragover`, and `drop` to manage the interaction and transfer data between elements.
Testing15
Unit: Testing small, isolated pieces of code (a single function). Integration: Testing how different modules work together. E2E (End-to-End): Testing the entire application flow from the user's perspective in a browser environment.
Jest is a delightful JavaScript Testing Framework with a focus on simplicity. It provides a test runner, assertion library (`expect`), and mocking capabilities. You use it to write tests for JS logic and React components.
React Testing Library (RTL) is a tool for testing React components. Its philosophy is to test components the way a user would (by interacting with text and labels) rather than testing implementation details like state or internal methods.
Enzyme: Focused on implementation (testing state, props, and internal methods). RTL: Focused on user behavior (testing what the user sees and interacts with). RTL is now the recommended standard for React testing.
Snapshot testing captures the rendered output of a component and saves it to a file. On subsequent runs, Jest compares the new output with the saved version. If they differ, the test fails, alerting you to unexpected UI changes.
Mocking is the process of creating a fake version of an external dependency (like an API call, a database, or a complex module) to isolate the code being tested. This ensures tests are fast, predictable, and don't rely on external services.
Code coverage is a metric that measures the percentage of your source code executed during testing. It identifies which parts of your codebase are 'covered' by tests and which are not. Common metrics include Line, Function, and Branch coverage.
TDD is a software development process where you write a failing test *before* writing the actual code. The cycle is: Red (write a failing test), Green (write the minimum code to pass), and Refactor (clean up the code).
Cypress is a next-generation front-end testing tool built for the modern web. You use it for End-to-End (E2E) testing because it runs directly in the browser, providing a visual debugger and automatic waiting for elements to appear.
Playwright is a framework for Web-platform testing and automation. It allows testing across all modern rendering engines including Chromium, WebKit, and Firefox with a single API. It is known for its speed and powerful 'auto-wait' features.
In Jest, you can test async code by: 1) Returning a Promise from the test. 2) Using the `done` callback. 3) Using async/await within the test function. 4) Using `.resolves` or `.rejects` matchers.
React hooks are tested using `@testing-library/react-hooks` or the built-in `renderHook` function in newer RTL versions. This allows you to wrap the hook in a virtual component and assert on its return values and effects.
MSW is an API mocking library that uses Service Workers to intercept network requests at the browser level. This allows you to use the same mock definitions for both development and testing without changing your application code.
Vitest is a blazing fast unit test framework powered by Vite. It is designed to be a drop-in replacement for Jest for projects using Vite, sharing the same configuration and providing a native ESM first approach.
Integration tests for APIs verify that the frontend and the backend communicate correctly. These tests check if the API endpoints return the expected data structures, status codes, and handle errors properly when integrated into the app flow.
Security15
XSS is an attack where malicious scripts are injected into trusted websites. Prevention: 1) Sanitize user input. 2) Escape HTML content. 3) Use a strong Content Security Policy (CSP). 4) Use modern frameworks like React that escape data by default.
CSRF is an attack that tricks a logged-in user into executing unwanted actions on a different website. Prevention: 1) Use Anti-CSRF tokens. 2) Set cookie attributes like `SameSite: Strict` or `Lax`. 3) Verify the 'Origin' or 'Referer' headers.
SQL Injection involves inserting malicious SQL code into input fields to manipulate a database. Prevention: 1) Use Prepared Statements (Parameterized Queries). 2) Use an ORM like Prisma or Sequelize. 3) Never concatenate user input directly into SQL strings.
CSP is an added layer of security that helps detect and mitigate certain types of attacks, including XSS and data injection. It is implemented via an HTTP header that tells the browser which sources of content (scripts, styles, images) are trusted.
HTTPS is the secure version of HTTP. It uses TLS/SSL to encrypt communication between the browser and the server. It is critical for: 1) Data Privacy. 2) Data Integrity (preventing tampering). 3) Authentication (verifying the website's identity).
The Same-Origin Policy (SOP) is a critical security mechanism that restricts how a document or script loaded by one origin can interact with a resource from another origin. An origin is defined by the protocol, domain, and port.
httpOnly: Prevents client-side scripts (JS) from accessing the cookie (mitigates XSS). secure: Ensures the cookie is only sent over encrypted (HTTPS) connections. These should always be used for sensitive data like Session IDs.
JWT (JSON Web Token) is an open standard for securely transmitting information as a JSON object. It consists of three parts: Header, Payload, and Signature. It is often used for stateless authentication.
OAuth 2.0 is an industry-standard protocol for authorization. It allows a website or app to access resources owned by a user on another site (like Google or Facebook) without the user sharing their password.
Authentication: Verifying who you are (Login). Authorization: Verifying what you have permission to do (Roles/Permissions).
Token-based authentication is a protocol where the server generates a cryptographically signed token (like a JWT) after a user logs in. The client stores this token (usually in `localStorage` or a cookie) and sends it in the header of every subsequent request, allowing for stateless communication.
In session-based authentication, the server creates a session and stores it in memory or a database after login. A unique `session_id` is sent to the client as a cookie. The server must look up this ID on every request to verify the user, making it stateful.
Passwords should never be stored in plain text. They must be hashed using a strong, slow hashing algorithm like bcrypt, scrypt, or Argon2. Additionally, a unique, random string called a salt should be added to each password before hashing to prevent rainbow table attacks.
bcrypt is a password-hashing function based on the Blowfish cipher. it incorporates a 'salt' to protect against rainbow table attacks and an adaptive 'work factor' (cost) that allows it to remain resistant to brute-force search attacks even as computing power increases.
The OWASP Top 10 is a standard awareness document for developers and web application security. It represents a broad consensus on the most critical security risks to web applications, such as Injection, Broken Access Control, and Cryptographic Failures.
Build Tools15
Webpack is a static module bundler for modern JavaScript applications. It takes all your project's files (JS, CSS, Images) and their dependencies and bundles them into one or more small files optimized for the browser. It solves the problem of managing complex dependency graphs and reducing HTTP requests.
Vite is a modern build tool that is significantly faster than Webpack. It uses Native ES Modules in the browser during development (avoiding the bundling step) and uses esbuild (written in Go) for pre-bundling dependencies. For production, it uses Rollup for highly optimized builds.
Babel is a JavaScript compiler (transpiler). It is primarily used to convert modern ECMAScript (ES6+) code into a backwards-compatible version of JavaScript that can run in older browsers or environments.
Development: Focused on developer experience (Fast HMR, Source Maps, helpful error messages). Production: Focused on performance (Minification, Uglification, Tree Shaking, Image Optimization, and removal of debug code).
HMR is a feature that injects updated modules into a running application without a full page refresh. This preserves the application state (e.g., data in a form or a modal's open state) while you are making code changes.
Rollup is a module bundler for JavaScript which compiles small pieces of code into something larger and more complex, such as a library or application. It is particularly well-known for its excellent Tree Shaking capabilities and is the engine behind Vite's production builds.
esbuild is an extremely fast JavaScript bundler and minifier written in Go. It is designed to be much faster than existing tools like Webpack or Rollup by leveraging parallelism and efficient memory management.
Turbopack is an incremental bundler optimized for JavaScript and TypeScript, written in Rust. Created by the Vercel team (Next.js), it is positioned as the successor to Webpack, claiming to be much faster for large-scale applications.
SWC (Speedy Web Compiler) is an extensible Rust-based platform for the next generation of fast developer tools. It is used for both compilation (like Babel) and bundling, offering significant speed improvements over its JavaScript-based predecessors.
Source maps are files that map your minified/transformed production code back to your original source code. They are useful because they allow you to debug your original code in the browser's developer tools, even if the code actually running is heavily optimized.
Minification: Removing unnecessary characters (whitespace, comments, newlines) to reduce file size. Uglification: A step further that renames variables and functions to shorter names to both reduce size and make the code harder to reverse-engineer.
CommonJS (CJS): Uses `module.exports` and `require()`; it is synchronous and used mainly in Node.js. ES Modules (ESM): Uses `export` and `import`; it is asynchronous, supports static analysis (Tree Shaking), and is the standard for modern browsers.
Dynamic import (`import()`) allows you to load modules asynchronously at runtime based on conditions. This is the primary mechanism used for Code Splitting, as it returns a promise that resolves to the module.
Module Federation allows a JavaScript application to dynamically load code from another application at runtime. It is a key technology for implementing Micro-frontends, as it allows multiple teams to deploy independently while sharing a single runtime.
A monorepo is a version control strategy where multiple distinct projects (e.g., a web app, a mobile app, and shared UI library) are stored in a single repository. Tools like Nx and Turborepo provide caching and task orchestration to make managing these large codebases fast and efficient.
Advanced10
Micro-frontends is an architectural style where a web application is broken down into small, semi-independent 'micro-apps' that are composed together. This allows multiple teams to work on, test, and deploy different parts of the UI independently using different technologies if needed.
BFF is a design pattern where you create a dedicated backend service for a specific frontend interface (e.g., one for Mobile, one for Web). This allows the backend to return exactly the data the specific UI needs, reducing over-fetching and simplifying frontend logic.
REST: Uses multiple endpoints that return fixed data structures (often leading to over-fetching). GraphQL: Uses a single endpoint where the client specifies *exactly* which fields it needs, providing much more flexibility and efficiency for complex data graphs.
tRPC is a framework for building end-to-end typesafe APIs without needing a schema or code generation. It allows you to share types between your backend and frontend directly, ensuring that if you change an API on the server, the frontend will immediately show a TypeScript error.
Web Components are a set of browser features that allow you to create reusable, encapsulated custom HTML tags. Shadow DOM provides CSS and DOM isolation, ensuring the styles inside your component don't leak out and affect the rest of the page.
Jamstack stands for JavaScript, APIs, and Markup. It is an architecture where the UI is pre-rendered into static HTML (Markup) and any dynamic functionality is handled via client-side JavaScript calling third-party or serverless APIs.
A headless CMS is a content management system that provides content as data through an API (REST or GraphQL) rather than being tied to a specific 'head' (frontend). This allows you to use the same content across Web, Mobile, and IoT devices.
Serverless allows developers to build and run applications without managing infrastructure. In frontend terms, this often means using Edge Functions or Cloud Functions to handle backend logic, scaling automatically with demand.
Edge computing involves moving computation and data storage closer to the user's location. For frontend developers, this means running middleware or SSR logic at the CDN level (Edge) to achieve the lowest possible latency.
A design system is a comprehensive set of standards for design and code (colors, typography, spacing) along with a library of reusable components (Buttons, Inputs). It ensures visual and functional consistency across all of a company's digital products.
Related question banks4
JavaScript Questions
108 questionsComprehensive collection of the most frequently asked JavaScript interview questions covering fundamentals, ES6+, async programming, DOM manipulation, objects, arrays, functions, and advanced concepts. Each answer is concise, detailed, and interview-ready.
TypeScript Questions
50 questionsA focused collection of the most critical TypeScript interview questions covering type system internals, advanced types, and best practices for modern development.
React.js Questions
100 questionsComprehensive collection of the most frequently asked React JS interview questions covering fundamentals, hooks, routing, testing, and advanced concepts. Each answer is concise and interview-ready.
React Native Questions
250 questionsComprehensive guide covering React Native fundamentals, Architecture, Styling, and Component Communication. Each answer is technically rigorous for professional interviews.