A complete collection of JavaScript interview questions and answers, explained with code examples and easy-to-understand concepts.
Perfect for developers preparing for interviews or revising JavaScript fundamentals.
Prepare for real interviews with 100+ curated JavaScript problems, runnable in your browser. Every question is selected and reviewed by experienced ex-FAANG interviewers so you practise what actually shows up in interviews — not filler content. We promise: no AI-generated fluff and no fake reviews — just high-quality problems, thoughtful explanations, and honest feedback to level up your interview game.
This repository is organized into comprehensive topic-based folders. Each folder contains detailed interview questions with code examples and explanations.
📁 Core JavaScript - Fundamental JavaScript concepts
- Data types, variables, operators
- Functions, scope, closures
- Objects, arrays, prototypes
- Error handling, modules
📁 ES6+ Features - Modern JavaScript (ES6 and beyond)
- Arrow functions, template literals, destructuring
- Classes, modules, promises
- Async/await, generators, proxies
- Maps, sets, symbols, iterators
📁 Arrays & Objects - Array and object manipulation
- Array methods (map, filter, reduce, etc.)
- Object methods and manipulation
- Advanced patterns and techniques
- Performance considerations
📁 DOM & Browser APIs - Browser interaction
- DOM manipulation and traversal
- Event handling and delegation
- Browser APIs (localStorage, geolocation, etc.)
- Web APIs (Fetch, WebSockets, Service Workers)
📁 Asynchronous Programming - Async patterns
- Callbacks, promises, async/await
- Event loop, microtasks/macrotasks
- Generators, async iterators
- Error handling in async code
📁 Node.js - Server-side JavaScript
- Node.js fundamentals and architecture
- File system operations, streams
- HTTP servers, Express.js, middleware
- Database integration, authentication, security
📁 Build Tools & Development - Development workflow
- Package managers (npm, yarn, pnpm)
- Bundlers (Webpack, Rollup, Vite)
- Task runners (Gulp, Grunt)
- Development tools (ESLint, Prettier, Husky)
📁 Testing - Testing methodologies
- Jest testing framework
- React Testing Library
- Unit, integration, and E2E testing
- Test coverage and best practices
📁 Frameworks - Popular JavaScript frameworks
- React: Components, hooks, state management, performance
- Vue.js: Vue instance, templates, Vuex, Composition API
- Angular: Components, services, dependency injection, CLI
📁 Performance - Optimization techniques
- Performance metrics and monitoring
- JavaScript optimization
- DOM and rendering performance
- Network optimization
📁 Design Patterns - Software design patterns
- Creational patterns (Singleton, Factory, Prototype)
- Structural patterns (Adapter, Decorator, Proxy)
- Behavioral patterns (Observer, Strategy, Command)
- Modern JavaScript patterns
-
Clone the repository
git clone https://github.com/codewithdhruba01/javascript-interview-questions.git cd javascript-interview-questions -
Install dependencies
npm install
-
Start development server
npm run serve
-
Run tests
npm test
- Browse by Topic: Choose a folder based on your area of interest
- Practice Questions: Each topic contains 15-30+ interview questions
- Code Examples: All questions include runnable code examples
- Progressive Learning: Start with fundamentals, then advance to complex topics
- Focus on Fundamentals: Master core JavaScript before frameworks
- Practice Coding: Implement concepts, don't just read
- Understand Trade-offs: Know when to use different approaches
- Stay Updated: Keep learning new JavaScript features
- System Design: Practice architectural questions
Contributions are welcome! Please read our contributing guidelines and submit pull requests for:
- New interview questions
- Code examples improvements
- Topic expansions
- Bug fixes
For backward compatibility, the original 50 questions are still available below:
JavaScript is a high-level, interpreted programming language used to make web pages dynamic and interactive.
It runs in browsers and on servers (with Node.js).
Features:
- Dynamic typing
- Prototype-based object orientation
- Event-driven and asynchronous
- Lightweight and flexible
Example:
console.log("Hello, JavaScript!");JavaScript supports primitive and non-primitive data types.
| Type | Example |
|---|---|
| String | "Hello" |
| Number | 42 |
| Boolean | true |
| Undefined | let a; |
| Null | let b = null; |
| Symbol | Symbol("id") |
| BigInt | 12345678901234567890n |
| Object | { name: "John" } |
Example:
let name = "John";
let age = 30;
let isLogged = true;
let user = { name, age };
console.log(typeof user); // "object"You can declare variables using var, let, or const.
var city = "Delhi"; // function scoped
let age = 25; // block scoped
const country = "India"; // constant, cannot be reassigned| Feature | var | let | const |
|---|---|---|---|
| Scope | Function | Block | Block |
| Re-declare | Allowed | Not allowed | Not allowed |
| Re-assign | Allowed | Allowed | Not allowed |
| Hoisting | Yes | Yes (uninitialized) | Yes (uninitialized) |
Example:
function example() {
console.log(a); // undefined
var a = 10;
let b = 20;
const c = 30;
console.log(a, b, c);
}
example();It returns the data type of a variable.
typeof 123; // "number"
typeof "Hello"; // "string"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof null; // "object"
typeof {}; // "object"
typeof Symbol(); // "symbol"NaN stands for Not-a-Number and indicates invalid number results.
console.log(0 / 0); // NaN
console.log(parseInt("A")); // NaN
console.log(typeof NaN); // "number"A callback function is a function passed as an argument to another function, to be executed later.
Example:
function greet(name, callback) {
console.log("Hi " + name);
callback();
}
function bye() {
console.log("Goodbye!");
}
greet("John", bye);Event delegation allows you to handle events at a parent level instead of adding listeners to individual child elements.
Example:
document.getElementById("list").addEventListener("click", function(e) {
if (e.target.tagName === "LI") {
console.log("You clicked on:", e.target.textContent);
}
});This approach improves performance and maintainability.
JavaScript objects can inherit properties and methods from other objects using the prototype chain.
Example:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log("Hello, I'm " + this.name);
};
const user = new Person("Alice");
user.greet(); // Hello, I'm Alicethis refers to the object that owns the current execution context.
| Context | Value of this |
|---|---|
| Global | window (browser) |
| Inside a function | undefined (in strict mode) |
| Inside object method | That object |
| Inside arrow function | Lexical this (inherits from parent) |
Example:
const user = {
name: "John",
show() {
console.log(this.name);
},
};
user.show(); // JohnA Promise represents a value that may be available now, later, or never. It helps handle asynchronous operations.
States:
- Pending
- Fulfilled
- Rejected
Example:
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("Done!"), 1000);
});
promise.then(result => console.log(result)); // Done!| Feature | null |
undefined |
|---|---|---|
| Meaning | Intentional absence of value | Variable declared but not assigned |
| Type | Object | Undefined |
| Example | let a = null; |
let b; |
Example:
let a = null;
let b;
console.log(a, typeof a); // null "object"
console.log(b, typeof b); // undefined "undefined"The event loop handles asynchronous code execution by monitoring the call stack and callback queue.
Flow:
- JS executes synchronous code (call stack)
- Async callbacks go to task queue
- Event loop moves them to stack when free
Example:
console.log("Start");
setTimeout(() => console.log("Async Task"), 0);
console.log("End");
// Output: Start → End → Async TaskEvent-driven programming is a paradigm where the flow of the program is determined by events — such as user actions (clicks, keypresses), messages from other programs, or sensor outputs.
Example:
document.getElementById("btn").addEventListener("click", () => {
console.log("Button was clicked!");
});Here, the function only executes when the click event happens.
Key Points:
- JavaScript is event-driven.
- It uses event listeners and callbacks.
- Allows asynchronous, interactive behavior on webpages.
| Feature | Synchronous | Asynchronous |
|---|---|---|
| Execution | Code runs line-by-line | Code can skip ahead while waiting |
| Blocking | Blocks further execution | Non-blocking |
| Example | Loops, calculations | API calls, file I/O |
Example:
console.log("Start");
setTimeout(() => console.log("Async Task"), 2000);
console.log("End");Output:
Start
End
Async Task
You can use try...catch...finally blocks or Promise .catch() for async code.
Example:
try {
let result = riskyOperation();
} catch (error) {
console.error("Something went wrong:", error);
} finally {
console.log("Operation completed");
}Also:
fetch("https://api.example.com")
.then(res => res.json())
.catch(err => console.error("Error fetching:", err));Modules allow splitting JavaScript code into separate files to improve maintainability.
Example:
// math.js
export function add(a, b) {
return a + b;
}
// main.js
import { add } from './math.js';
console.log(add(2, 3)); // 5Benefits:
- Code reusability
- Clear organization
- Avoids global scope pollution
Generators are special functions that can pause and resume their execution using the yield keyword.
Example:
function* count() {
yield 1;
yield 2;
yield 3;
}
const counter = count();
console.log(counter.next().value); // 1Use Case: Useful for lazy evaluation and asynchronous iteration.
Arrow functions are a shorter syntax for writing functions introduced in ES6.
Example:
const add = (a, b) => a + b;
console.log(add(5, 10)); // 15Advantages:
- Concise syntax
- Lexically binds
this - Great for callbacks and inline functions
Currying transforms a function with multiple arguments into a sequence of functions that take one argument each.
Example:
function curry(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}
console.log(curry(2)(3)(4)); // 9Benefits:
- Reusability
- Function composition
- Delayed execution
Memoization is an optimization technique to cache results of expensive function calls.
Example:
function memoize(fn) {
const cache = {};
return function(x) {
if (x in cache) return cache[x];
return (cache[x] = fn(x));
};
}
const square = memoize(x => x * x);
console.log(square(4)); // Computed
console.log(square(4)); // CachedThe prototype chain is the mechanism through which objects inherit properties and methods from other objects.
Example:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return `Hello ${this.name}`;
};
const user = new Person("John");
console.log(user.greet()); // Hello JohnInheritance works via __proto__ links between objects.
Functions in JavaScript are treated like variables — they can be passed as arguments, returned, and assigned.
Example:
function greet(name) {
return `Hello ${name}`;
}
function logGreeting(fn) {
console.log(fn("Alice"));
}
logGreeting(greet);A higher-order function takes one or more functions as arguments or returns a function.
Example:
function multiplier(factor) {
return function(num) {
return num * factor;
};
}
const double = multiplier(2);
console.log(double(5)); // 10Arrow functions (=>) are a type of lambda expression — a compact way to define anonymous functions.
Example:
const greet = name => `Hello, ${name}!`;
console.log(greet("John"));Difference: Arrow functions do not have their own this or arguments binding.
You can list out the differences in a tabular format.
| var | let |
|---|---|
| Available since the beginning of JavaScript | Introduced in ES6 |
| Function scoped | Block scoped |
| Hoisted and initialized as undefined | Hoisted but not initialized |
| Can be re-declared | Cannot be re-declared |
Example:
function userDetails(username) {
if (username) {
console.log(salary); // undefined due to hoisting
// console.log(age); // ReferenceError: Cannot access 'age' before initialization
let age = 30;
var salary = 10000;
}
console.log(salary); // 10000 (function scope)
// console.log(age); // Error: age is not defined (block scope)
}
userDetails("John");encodeURI() function is used to encode a URL. This function requires a URL string as a parameter and returns that encoded string.
decodeURI() function is used to decode a URL. This function requires an encoded URL string as a parameter and returns that decoded string.
Note: If you want to encode characters such as
/ ? : @ & = + $ #, then you need to useencodeURIComponent()instead ofencodeURI().
let uri = "employeeDetails?name=john&occupation=manager";
let encoded_uri = encodeURI(uri);
let decoded_uri = decodeURI(encoded_uri);
console.log("Encoded URI:", encoded_uri);
console.log("Decoded URI:", decoded_uri);Memoization is a functional programming technique that attempts to increase a function’s performance by caching its previously computed results. Each time a memoized function is called, its parameters are used to index the cache. If the data is already present, it returns the cached result without executing the entire function again. Otherwise, the function is executed and the new result is added to the cache.
Let’s take an example of an adding function with memoization:
const memoizeAddition = () => {
let cache = {};
return (value) => {
if (value in cache) {
console.log("Fetching from cache");
return cache[value]; // Here, cache.value cannot be used as property name starts with a number
} else {
console.log("Calculating result");
let result = value + 20;
cache[value] = result;
return result;
}
};
};
// returned function from memoizeAddition
const addition = memoizeAddition();
console.log(addition(20)); // output: 40 calculated
console.log(addition(20)); // output: 40 cachedHoisting is a JavaScript mechanism where variables, function declarations, and classes are moved to the top of their scope before code execution. Remember that JavaScript only hoists declarations, not initializations.
Let’s take a simple example of variable hoisting:
console.log(message); // output: undefined
var message = "The variable has been hoisted";The above code looks like this to the interpreter:
var message;
console.log(message);
message = "The variable has been hoisted";In the same fashion, function declarations are hoisted too:
message("Good morning"); // Good morning
function message(name) {
console.log(name);
}JavaScript is single-threaded, meaning it executes one piece of code at a time on a single main thread.
To handle asynchronous operations (like setTimeout, fetch, or Promises), JavaScript uses the event loop.
The event loop continuously checks:
- If the call stack (where JS executes functions) is empty.
- If the task queues have any pending callbacks to run.
- It then takes the next task from the queue and pushes it onto the call stack.
There are two major queues where async callbacks are placed:
These are large, independent units of work. Examples:
setTimeout()setInterval()setImmediate()(Node.js)I/O eventsrequestAnimationFrame()
After each macrotask, the event loop checks for microtasks before moving to the next one.
Microtasks are smaller, higher-priority tasks meant to run immediately after the current execution context, before any new macrotask starts.
Examples:
Promise.then(),Promise.catch(),Promise.finally()queueMicrotask()MutationObserver
All queued microtasks run right after the current script or macrotask finishes, and before the next macrotask starts.
console.log("Start");
setTimeout(() => {
console.log("Macrotask");
}, 0);
Promise.resolve().then(() => {
console.log("Microtask");
});
console.log("End");Output:
Start
End
Microtask
Macrotask
The DOM (Document Object Model) is a representation of the HTML structure as objects, allowing JavaScript to interact with and manipulate the content and layout.
Use document.getElementById('id') to select an element by its ID.
-
How do you add a class to an HTML element using JavaScript?
-> Useelement.classList.add('class-name')to add a class to an element. -
How do you remove an element from the DOM in JavaScript?
-> Useelement.remove()to remove an element from the DOM. -
How do you change the text content of an element in JavaScript?
-> Useelement.textContent = 'New text'to change the text of an element. -
What is a for loop in JavaScript?
-> A for loop is used to execute a block of code a certain number of times. Example: for(let i = 0; i < 5; i++){ console.log(i); }. -
What is an if-else statement in JavaScript?
-> Anif-elsestatement executes a block of code if a condition is true, otherwise it runs the code in theelseblock. -
What is the purpose of the switch statement in JavaScript?
-> Aswitchstatement allows you to execute different blocks of code based on the value of a variable. -
What is a while loop in JavaScript?
-> Awhileloop repeatedly executes a block of code as long as a specified condition is true. -
How do you exit a loop in JavaScript?
-> Use thebreakstatement to exit a loop prematurely.
Arrow functions are a shorthand syntax for writing functions in JavaScript. Example:
const add = (a, b) => a + b;.
-
What is destructuring in JavaScript?
-> Destructuring allows you to extract values from arrays or objects into variables. Example:const [a, b] = [1, 2];. -
What is template literals in JavaScript?
-> Template literals are string literals that allow embedded expressions, using backticks (``) and ${} for placeholders. -
What are default parameters in JavaScript?
-> Default parameters allow you to initialize function parameters with default values if no value is passed. -
What is the spread operator in JavaScript?
-> Thespreadoperator (...) allows an iterable to expand in places where multiple arguments are expected. -
What is the rest parameter in JavaScript?
-> Therestparameter (...args) allows you to pass an indefinite number of arguments to a function. -
What are promises in JavaScript?
-> Promises represent asynchronous operations that either resolve or reject. Example:new Promise((resolve, reject) => {}).
A pure function is a function whose output depends only on its input arguments and produces no side effects. This means:
- Given the same inputs, it will always return the same output.
- It does not modify any external variables, objects, or state.
To understand this better, let’s compare pure and impure functions.
let numbers = [];
const impureAdd = (num) => {
return numbers.push(num);
};const pureAdd = (num) => (arr) => {
return arr.concat([num]);
};console.log(impureAdd(5)); // Output: 1
console.log(numbers); // Output: [5]
console.log(pureAdd(10)(numbers)); // Output: [5, 10]
console.log(numbers); // Still [5]- It modifies the external array
numbers. - Each call changes the program's overall state.
- The returned value depends on how many times the function was called earlier.
Because it alters something outside itself, it is not a pure function.
- It never changes the original array.
- Instead, it creates and returns a new array with the added value.
- Same input → same output, with no side effects.
In ES6, JavaScript classes are mainly syntactic sugar over JavaScript’s prototype-based inheritance. Before ES6, inheritance was done using function constructors and prototypes, like this:
function Bike(model, color) {
this.model = model;
this.color = color;
}
Bike.prototype.getDetails = function () {
return this.model + " bike has " + this.color + " color";
};With ES6, the same structure can be written more cleanly using the class syntax:
class Bike {
constructor(model, color) {
this.model = model;
this.color = color;
}
getDetails() {
return this.model + " bike has " + this.color + " color";
}
}Modules refer to small units of independent, reusable code and also act as the foundation of many JavaScript design patterns. Most of the JavaScript modules export an object literal, a function, or a constructor
Scope is the accessibility of variables, functions, and objects in some particular part of your code during runtime. In other words, scope determines the visibility of variables and other resources in areas of your code.
We need modules in JavaScript because they help:
- Break code into smaller parts (easy to manage).
- Increase reusability (use the same code multiple times).
- Prevent global scope pollution (avoid variable conflicts).
- Make maintenance easier (useful in large projects).
- Keep code clean, organized, and secure.
Conclusion: Modules make JavaScript code organized, reusable, safe, and easier to maintain.
Service worker can't access the DOM directly. But it can communicate with the pages it controls by responding to messages sent via the postMessage interface, and those pages can manipulate the DOM.
postMessage is a method that allows secure cross-origin communication between different Window objects — such as between a parent page and a popup it opened, or between a webpage and an embedded iframe. Normally, scripts running on different pages cannot access each other unless they follow the same-origin policy, which requires the pages to share the same protocol, host, and port. The postMessage API provides a safe way to bypass this restriction and exchange data across different origins.
A cookie in JavaScript is a small piece of data stored in the browser. It is used to remember the user, store login sessions, preferences, or track activity.
In simple words:
Cookie = small data stored in the browser
Example: remembering username, saving theme, storing cart items, or tracking sessions.
document.cookie = "username=John; expires=Fri, 31 Dec 2025 23:59:59 GMT; path=/";console.log(document.cookie);document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";A Promise is a JavaScript object that represents the eventual result of an asynchronous operation—whether it succeeds or fails. It serves as a placeholder for a value that isn’t available yet but will be provided at some point in the future once the operation completes.
In simple words:
Promise = an object that guarantees you will get the result in the future
It handles the result of async tasks (success or error).
- Pending → The result is not available yet
- Fulfilled → The operation completed successfully
- Rejected → The operation failed (error)
let myPromise = new Promise((resolve, reject) => {
let success = true;
if (success) {
resolve("Operation Successful!");
} else {
reject("Something went wrong!");
}
});
myPromise
.then(result => console.log(result)) // Success case
.catch(error => console.log(error)); // Error caseWe need Promises to handle asynchronous operations in a clean and manageable way. JavaScript runs tasks one by one, so when something takes time—like fetching data from a server—Promises help us handle the result without blocking the rest of the code.
1. To handle asynchronous tasks easily
Example: fetching data from an API, reading files, waiting for timers.
2. To avoid “callback hell”
Promises provide .then() and .catch() instead of deeply nested callback functions.
3. To write cleaner and more readable code
Promises, especially with async/await, make asynchronous code look like synchronous code.
4. Better error handling
.catch() handles all errors in one place, making debugging easier.
5. Promises chain smoothly
You can run async operations step-by-step using .then() chaining.
A closure is a function that remembers and can access variables from its outer (lexical) scope, even after the outer function has finished executing. It is created when an inner function uses variables of its enclosing function.
The closure has access to three scope chains:
i. Its own scope – variables defined inside its curly braces ii. Outer function’s scope – variables of the enclosing function iii. Global scope – globally declared variables
function Welcome(name) {
var greetingInfo = function (message) {
console.log(message + " " + name);
};
return greetingInfo;
}
var myFunction = Welcome("John");
myFunction("Welcome"); // Output: Welcome John
myFunction("Hello Mr."); // Output: Hello Mr. JohnIn the above code:
Welcome()is the outer functiongreetingInfo()is the inner function- The inner function uses the variable
namefrom the outer function
Even after the Welcome() function has finished execution,
the inner function still remembers and has access to name.
This behavior of remembering variables from the outer scope is called a closure.
IndexedDB is a low-level API for client-side storage of larger amounts of structured data, including files/blobs. This API uses indexes to enable high-performance searches of this data.
Collation determines how strings are compared, sorted, and matched. It controls whether text comparison is case-sensitive or case-insensitive and how characters are ordered based on language rules.
Example: In a case-insensitive collation, “Apple” and “apple” are treated as the same, while in case-sensitive collation they are considered different.
Web Storage allows web applications to store data locally in the user’s browser, such as user preferences, login state, or theme settings. It improves performance by reducing server requests and provides a better user experience.
To delete a cookie, we re-set the same cookie with the same name and path, but with an expiration date in the past, which tells the browser to remove it.
Example:
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";Promise.all() takes an array of promises and returns a single promise. It resolves with an array of results when all promises succeed, but if any promise rejects, it immediately rejects with that error.
Example:
Promise.all([
fetch('/api/user'),
fetch('/api/posts'),
fetch('/api/comments')
])
.then(results => {
console.log("All promises resolved", results);
})
.catch(error => {
console.error("One promise failed", error);
});In JavaScript, when we try to access an object property that is not defined or a variable that has been declared but not initialized, JavaScript returns undefined.
Example:
let user = { name: "Dhrub" };
console.log(user.age); // undefined (property does not exist)Important Points:
- undefined is a primitive data type
- It means absence of a value
- Different from null (null is intentionally assigned)