JavaScript is one of the most important technologies for modern web development. For experienced developers, JavaScript interviews go beyond basic syntax and often cover closures, prototypes, asynchronous programming, promises, the event loop, browser APIs, performance, security, modules, memory management, and application architecture.
This guide covers 50 important JavaScript interview questions with answers and explanations to help experienced developers prepare for technical interviews.
JavaScript Fundamentals and Advanced Concepts
1. What is the difference between var, let, and const?
Answer
All three are used to declare variables, but they differ in scope, hoisting behavior, and reassignment.
var a = 10;
let b = 20;
const c = 30;
varis function-scoped.letis block-scoped.constis block-scoped.letandconstcannot be accessed before their declaration because of the Temporal Dead Zone.A
constvariable cannot be reassigned.
However, objects declared with const can still be mutated.
const user = { name: "John" };
user.name = "David";
This is valid because the object reference itself was not reassigned.
2. What is hoisting in JavaScript?
Answer
Hoisting is the behavior where JavaScript processes declarations before executing the associated code.
For example:
console.log(a);
var a = 10;
This behaves conceptually like:
var a;
console.log(a);
a = 10;
Therefore, the output is:
undefined
Function declarations are also hoisted:
sayHello();
function sayHello() {
console.log("Hello");
}
let and const are also created during the environment setup, but accessing them before their declaration results in a ReferenceError because of the Temporal Dead Zone.
3. What is the Temporal Dead Zone (TDZ)?
Answer
The Temporal Dead Zone is the period between entering a scope and the point where a let or const variable is initialized.
console.log(name);
let name = "John";
This throws:
ReferenceError
Explanation
The variable exists in the scope but cannot be accessed before its declaration is evaluated.
Understanding TDZ is important when debugging initialization-related problems.
4. What is the difference between == and ===?
Answer
== performs loose equality comparison and may perform type coercion.
=== performs strict equality comparison without implicit type conversion.
5 == "5"; // true
5 === "5"; // false
Recommendation
In most application code, prefer === because it makes type comparisons explicit and reduces unexpected coercion behavior.
5. What are primitive and reference values in JavaScript?
Answer
JavaScript has primitive types such as:
String
Number
BigInt
Boolean
Undefined
Symbol
Null
Objects, arrays, and functions are non-primitive values.
Primitive values are immutable values, while objects are mutable.
Example:
let a = 10;
let b = a;
b = 20;
Changing b does not change a.
With objects:
let user1 = { name: "John" };
let user2 = user1;
user2.name = "David";
Both variables reference the same object, so user1.name also becomes "David".
6. What is a closure in JavaScript?
Answer
A closure occurs when a function retains access to variables from its surrounding lexical scope even after the outer function has finished executing.
function counter() {
let count = 0;
return function () {
count++;
return count;
};
}
const increment = counter();
console.log(increment()); // 1
console.log(increment()); // 2
Explanation
The returned function remembers the count variable.
Closures are commonly used for:
Data privacy
Function factories
Callbacks
Event handlers
Memoization
State management
7. What is lexical scope?
Answer
Lexical scope means that the scope of a variable is determined by where the code is written, not where the function is called.
const name = "John";
function greet() {
console.log(name);
}
greet();
The function can access name because it was defined in an outer lexical scope.
Explanation
Closures are based on lexical scoping.
8. What is the difference between shallow copy and deep copy?
Answer
A shallow copy copies the top-level structure but nested objects can still be shared.
const user = {
name: "John",
address: {
city: "Delhi"
}
};
const copy = { ...user };
copy.address still refers to the same nested object.
A deep copy creates independent nested structures.
Modern JavaScript provides:
const copy = structuredClone(user);
Explanation
Deep copying is useful when independent nested state is required, but it should not automatically be used everywhere because it can have performance and data-type implications.
9. What is the difference between null and undefined?
Answer
undefined generally means a value has not been assigned or is unavailable.
let value;
console.log(value); // undefined
null is an explicit representation of an intentional absence of a value.
let user = null;
A useful distinction is:
undefined→ value is not available/assigned.null→ application intentionally represents no value.
10. What is the difference between Object.freeze() and Object.seal()?
Answer
Object.freeze() prevents modifications to an object's existing properties and prevents adding or deleting properties.
const user = {
name: "John"
};
Object.freeze(user);
Object.seal() prevents adding or deleting properties, but existing writable properties can still be changed.
Object.seal(user);
Important
Both are shallow operations. Nested objects are not automatically frozen or sealed.
Functions, Objects and Prototypes
11. What is the prototype chain in JavaScript?
Answer
Objects in JavaScript can inherit properties and methods through their prototype chain.
For example:
const user = {
name: "John"
};
console.log(user.toString());
toString() is not defined directly on user. JavaScript searches the object's prototype chain to find it.
Explanation
Prototype-based inheritance is fundamental to JavaScript's object model.
12. What is prototypal inheritance?
Answer
Prototypal inheritance allows an object to inherit properties and methods from another object through its prototype.
const person = {
greet() {
console.log("Hello");
}
};
const user = Object.create(person);
user.greet();
The user object can access greet() through its prototype.
13. How do JavaScript classes work internally?
Answer
JavaScript classes provide cleaner syntax for creating objects and working with prototypes.
class User {
constructor(name) {
this.name = name;
}
greet() {
return `Hello ${this.name}`;
}
}
Methods defined on the class are generally placed on the class's prototype.
Therefore, JavaScript classes are a syntax abstraction over JavaScript's prototype-based object model rather than a completely separate inheritance mechanism.
14. What is the difference between regular functions and arrow functions?
Answer
Arrow functions have different behavior for this, arguments, and constructors.
const add = (a, b) => a + b;
Arrow functions do not have their own this. They capture this from the surrounding lexical scope.
Regular functions determine this based on how they are called.
Important
Arrow functions cannot be used with new as constructors.
15. How does this work in JavaScript?
Answer
The value of this depends largely on how a function is called.
const user = {
name: "John",
greet() {
console.log(this.name);
}
};
user.greet();
Here, this refers to user.
For arrow functions, this is lexically inherited from the surrounding scope.
Interview Tip
Do not explain this simply as "the current object." Its value depends on the invocation context.
16. What are call(), apply(), and bind()?
Answer
They allow explicit control over a function's this value.
call()
Arguments are passed individually.
greet.call(user, "Hello");
apply()
Arguments are passed as an array-like collection.
greet.apply(user, ["Hello"]);
bind()
Returns a new function with this bound.
const fn = greet.bind(user);
fn();
17. What is currying in JavaScript?
Answer
Currying transforms a function with multiple arguments into a sequence of functions that each accept fewer arguments.
function add(a) {
return function (b) {
return function (c) {
return a + b + c;
};
};
}
console.log(add(2)(3)(4)); // 9
Currying can be useful for function composition and reusable operations.
18. What is memoization?
Answer
Memoization is an optimization technique where the result of an expensive function is cached so that repeated calls with the same input can reuse the result.
function memoize(fn) {
const cache = new Map();
return function (value) {
if (cache.has(value)) {
return cache.get(value);
}
const result = fn(value);
cache.set(value, result);
return result;
};
}
Common Uses
Expensive calculations
Recursive algorithms
Repeated API-independent computations
Derived application state
Asynchronous JavaScript
19. What is the JavaScript event loop?
Answer
JavaScript executes synchronous code on the call stack. Asynchronous operations are handled through the host environment, and their callbacks are scheduled for execution when the stack becomes available.
A simplified model involves:
Call Stack
↓
Host APIs
↓
Task/Microtask Queues
↓
Event Loop
↓
Call Stack
Explanation
The event loop enables JavaScript to handle asynchronous operations without blocking the main execution thread for every operation.
20. What is the difference between microtasks and macrotasks?
Answer
Examples of microtasks include:
Promise callbacks
queueMicrotask()
Examples of tasks/macrotasks include:
setTimeout()setInterval()Certain browser events
Consider:
console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C"));
console.log("D");
The output is:
A
D
C
B
Explanation
After the synchronous code completes, microtasks are generally processed before the next task is taken from the task queue.
21. What are Promises in JavaScript?
Answer
A Promise represents the eventual completion or failure of an asynchronous operation.
It has three conceptual states:
Pending
Fulfilled
Rejected
Example:
const promise = fetch("/api/users");
promise
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
Promises make asynchronous code easier to compose than deeply nested callbacks.
22. What is async/await?
Answer
async/await provides syntax for working with Promises in a more synchronous-looking style.
async function getUsers() {
try {
const response = await fetch("/api/users");
const data = await response.json();
return data;
} catch (error) {
console.error(error);
}
}
An async function always returns a Promise.
Important
await does not block the entire JavaScript runtime. It pauses the execution of that async function until the awaited Promise settles.
23. What is the difference between Promise.all() and Promise.allSettled()?
Answer
Promise.all() rejects as soon as one of its input Promises rejects.
const results = await Promise.all([
fetchUsers(),
fetchProducts(),
fetchOrders()
]);
It is useful when all operations are required for successful completion.
Promise.allSettled() waits for every Promise and reports each outcome.
const results = await Promise.allSettled([
fetchUsers(),
fetchProducts(),
fetchOrders()
]);
This is useful when you want to process successful and failed operations independently.
24. What is the difference between Promise.race() and Promise.any()?
Answer
Promise.race() settles when the first input Promise settles, whether fulfilled or rejected.
Promise.any() fulfills when the first input Promise fulfills. It rejects only when all input Promises reject.
Example use cases:
race()→ timeout behavior or first-settled operationany()→ try multiple independent sources and accept the first successful response
25. How do you handle errors in asynchronous JavaScript?
Answer
With async/await, use try/catch.
async function loadData() {
try {
const response = await fetch("/api/data");
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error(error);
}
}
Explanation
A robust application should distinguish between:
Network failures
HTTP errors
Validation errors
Authentication failures
Unexpected application errors
26. What is callback hell?
Answer
Callback hell occurs when asynchronous callbacks become deeply nested and difficult to maintain.
Example:
getUser(function (user) {
getOrders(user.id, function (orders) {
getPayment(orders[0], function (payment) {
// More nested logic
});
});
});
Promises and async/await can make such workflows easier to read and maintain.
Browser and DOM
27. What is event delegation?
Answer
Event delegation involves placing an event listener on a parent element instead of attaching separate listeners to every child.
document.querySelector("#users").addEventListener("click", function (event) {
if (event.target.matches(".delete")) {
console.log("Delete clicked");
}
});
Benefits
Fewer event listeners
Better handling of dynamically created elements
Potentially lower memory overhead
Centralized event handling
28. What is event bubbling and event capturing?
Answer
DOM events can travel through the document in phases.
A simplified model is:
Capturing
↓
Target
↓
Bubbling
By default, many event listeners operate during the bubbling phase.
You can listen during capturing:
element.addEventListener("click", handler, true);
Understanding propagation is important when debugging complex UI interactions.
29. What is the difference between preventDefault() and stopPropagation()?
Answer
preventDefault() prevents the browser's default action.
event.preventDefault();
For example, it can prevent a link from navigating.
stopPropagation() stops the event from continuing through its propagation path.
event.stopPropagation();
They solve different problems and should not be treated as interchangeable.
30. What is the difference between DOMContentLoaded and load?
Answer
DOMContentLoaded fires when the HTML document has been parsed and the DOM is ready.
document.addEventListener("DOMContentLoaded", () => {
// DOM is ready
});
load fires after the page and its dependent resources, such as images, have finished loading.
For DOM initialization, DOMContentLoaded is often the more appropriate event.
Performance and Memory
31. How can you improve JavaScript application performance?
Answer
Common approaches include:
Reduce unnecessary JavaScript
Code splitting
Lazy loading
Minification and compression
Efficient DOM updates
Debouncing expensive events
Avoiding unnecessary network requests
Caching appropriate data
Reducing bundle size
Using Web Workers for suitable CPU-heavy tasks
Profiling before optimizing
Important
Do not optimize based only on assumptions. Use browser performance tools and real measurements.
32. What is debouncing?
Answer
Debouncing ensures that a function runs only after a specified period has passed without another invocation.
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
Common Uses
Search boxes
Window resizing
Form validation
Autocomplete
33. What is throttling?
Answer
Throttling limits how frequently a function can execute.
It is useful for high-frequency events such as:
Scroll
Mouse movement
Resize
Pointer events
Difference
Debounce: Wait until activity stops.
Throttle: Execute at controlled intervals during activity.
34. What causes memory leaks in JavaScript?
Answer
A memory leak occurs when memory that is no longer needed remains reachable and therefore cannot be reclaimed.
Common causes include:
Unremoved event listeners
Long-lived timers
Unnecessary global references
Detached DOM nodes still referenced by JavaScript
Growing caches
Closures retaining unnecessary objects
Example
const cache = new Map();
function storeData(key, data) {
cache.set(key, data);
}
If the cache grows indefinitely, it can consume significant memory.
35. What is garbage collection in JavaScript?
Answer
JavaScript engines automatically reclaim memory that is no longer reachable by the running program.
Modern engines commonly use tracing garbage collection techniques.
Developers generally do not manually free memory. Instead, they should ensure that unnecessary objects are no longer referenced.
Modern JavaScript
36. What are ES modules?
Answer
ES modules provide a standardized way to organize JavaScript code using import and export.
// user.js
export function getUser() {
// ...
}
Then:
import { getUser } from "./user.js";
Benefits
Better code organization
Explicit dependencies
Reusability
Easier static analysis
Support for tree-shaking in build systems
37. What is dynamic import()?
Answer
Dynamic import loads a module asynchronously at runtime.
const module = await import("./reports.js");
This can be useful for:
Lazy loading
Code splitting
Feature-based loading
Reducing initial JavaScript payload
38. What is optional chaining?
Answer
Optional chaining allows safe access to nested properties.
const city = user?.address?.city;
If user or address is null or undefined, the expression returns undefined instead of throwing an error.
39. What is the nullish coalescing operator?
Answer
The ?? operator provides a fallback only when the left-hand value is null or undefined.
const name = user.name ?? "Guest";
This differs from ||.
const count = 0 || 10; // 10
const count2 = 0 ?? 10; // 0
This distinction is important when values such as 0, false, or an empty string are valid.
40. What are generators in JavaScript?
Answer
Generators are functions that can pause and resume execution.
function* numbers() {
yield 1;
yield 2;
yield 3;
}
const generator = numbers();
console.log(generator.next());
console.log(generator.next());
Generators return iterator objects and can be useful for:
Lazy sequences
Iteration
Streaming-style processing
Custom iteration behavior
APIs, Security and Architecture
41. What is CORS?
Answer
CORS, or Cross-Origin Resource Sharing, is a browser security mechanism that controls whether a web page can access resources from another origin.
A server can explicitly allow origins through HTTP response headers.
For example:
Access-Control-Allow-Origin
Important
CORS is primarily enforced by browsers. It is not a substitute for authentication or authorization.
42. How can you prevent XSS attacks in JavaScript applications?
Answer
Cross-Site Scripting (XSS) occurs when untrusted content is interpreted as executable HTML or script.
Important defenses include:
Escape untrusted output
Prefer
textContentfor plain textAvoid unsafe use of
innerHTMLSanitize HTML when HTML input is genuinely required
Use Content Security Policy where appropriate
Validate input on the server
Use secure cookie attributes
Example:
element.textContent = userInput;
This is generally safer than directly inserting untrusted input as HTML.
43. How should sensitive data be handled in frontend JavaScript?
Answer
Sensitive information should not be considered secret simply because it is hidden in frontend code.
Never hard-code:
Database passwords
Private API keys
Secret tokens
Server credentials
Frontend JavaScript is delivered to the client and can be inspected.
Sensitive operations should be performed on trusted backend systems.
44. What is the difference between localStorage, sessionStorage, and cookies?
Answer
localStorage
Data persists across browser sessions until removed.
localStorage.setItem("theme", "dark");
sessionStorage
Data generally lasts for the lifetime of the page session.
sessionStorage.setItem("step", "2");
Cookies
Cookies can be sent to the server with requests depending on their attributes.
For authentication-related cookies, security attributes such as:
HttpOnlySecureSameSite
are important.
Interview Tip
Do not automatically recommend localStorage for authentication tokens without discussing the application's threat model, especially XSS risk.
45. How does fetch() work?
Answer
fetch() provides a Promise-based API for making network requests.
async function getUsers() {
const response = await fetch("/api/users");
if (!response.ok) {
throw new Error("Request failed");
}
return response.json();
}
Important
fetch() does not automatically reject its Promise for HTTP error status codes such as 404 or 500. You should check response.ok or response.status.
Advanced JavaScript and System Design
46. How would you design a scalable frontend JavaScript application?
Answer
A scalable frontend should have clear separation of concerns.
A possible structure is:
Application
│
├── Components
├── Services
├── State
├── Utilities
├── API Layer
├── Routing
└── Shared Modules
Important considerations include:
Modular architecture
Clear state ownership
Reusable components
API abstraction
Error handling
Lazy loading
Code splitting
Testing
Performance monitoring
Consistent coding standards
The architecture should be appropriate for the application's size rather than introducing unnecessary complexity.
47. How would you debug a slow JavaScript application?
Answer
I would first reproduce and measure the problem.
A practical process is:
Check browser Performance tools.
Identify long-running JavaScript tasks.
Check network requests.
Analyze bundle size.
Look for unnecessary rendering.
Check memory usage.
Identify expensive loops or calculations.
Review event listeners.
Check API response times.
Measure improvements after each change.
Key Principle
Measure → identify bottleneck → optimize → measure again.
48. How would you prevent duplicate API requests?
Answer
The approach depends on the application.
Possible strategies include:
Debouncing user input
Request caching
Request deduplication
Aborting obsolete requests
Tracking requests already in progress
Client-side state management
For example, when implementing search autocomplete, AbortController can cancel an outdated request:
const controller = new AbortController();
fetch("/api/search?q=javascript", {
signal: controller.signal
});
// Cancel request
controller.abort();
This prevents outdated requests from unnecessarily consuming resources.
49. What is AbortController and where can it be used?
Answer
AbortController provides a standard way to signal cancellation to APIs that support abort signals.
Example:
const controller = new AbortController();
fetch("/api/users", {
signal: controller.signal
})
.then(response => response.json())
.catch(error => {
if (error.name === "AbortError") {
console.log("Request cancelled");
}
});
controller.abort();
Common Uses
Canceling fetch requests
Search/autocomplete
Component cleanup
Preventing outdated requests
Canceling long-running supported operations
50. What are the most important principles for writing production-quality JavaScript?
Answer
Production-quality JavaScript should focus on:
Readability
Maintainability
Correctness
Security
Performance
Testability
Error handling
Modularity
Accessibility
Observability
A senior developer should also consider:
Requirements
↓
Architecture
↓
Implementation
↓
Testing
↓
Performance
↓
Security
↓
Monitoring
↓
Maintenance
Explanation
Experienced developers are expected to think beyond whether the code simply works.
They should consider:
What happens when the API fails?
What happens with thousands of users?
What happens on a slow network?
Can the code be maintained by another developer?
Could untrusted input create a security issue?
Can unnecessary work be avoided?
How will production problems be diagnosed?
These considerations distinguish basic JavaScript knowledge from production-level engineering.
Quick Revision: 50 JavaScript Interview Topics
Before an experienced-level JavaScript interview, revise these topics:
var,let, andconstHoisting
Temporal Dead Zone
==vs===Primitive and reference values
Shallow vs deep copy
nullvsundefinedObject.freeze()vsObject.seal()Closures
Lexical scope
Prototype chain
Prototypal inheritance
JavaScript classes
Arrow functions
thiscall(),apply(),bind()Currying
Memoization
Event loop
Microtasks and tasks
Promises
async/awaitPromise.all()Promise.allSettled()Promise.race()Promise.any()Error handling
Event delegation
Event bubbling/capturing
preventDefault()vsstopPropagation()DOMContentLoadedvsloadJavaScript performance
Debouncing
Throttling
Memory leaks
Garbage collection
ES modules
Dynamic imports
Optional chaining
Nullish coalescing
Generators
CORS
XSS prevention
Frontend security
Storage mechanisms
Fetch API
Frontend architecture
Debugging performance
Request cancellation
Production-quality JavaScript
Final Interview Tip
For experienced JavaScript candidates, interviewers often evaluate how you think, not just whether you remember JavaScript syntax.
When answering advanced questions, try to explain:
Concept → Practical example → Trade-off → Real-world use case
For example, when discussing caching, don't stop at explaining what caching is. Explain what you would cache, how you would invalidate it, what could go wrong, and how you would measure whether it actually improves performance.
This approach demonstrates practical engineering experience rather than memorized knowledge.