Top 25 JavaScript Interview Questions
Curated questions covering closures, hoisting, promises, async/await, event loop, ES6+, prototypes, and DOM manipulation.
What is the difference between var, let, and const?
- var — function-scoped, hoisted (initialized as undefined), can be re-declared.
- let — block-scoped, hoisted but not initialized (temporal dead zone), cannot be re-declared.
- const — block-scoped, must be initialized, cannot be reassigned (but object properties can be mutated).
What is a closure in JavaScript?
A closure is a function that retains access to variables from its outer (enclosing) scope even after the outer function has returned. Closures are used for data encapsulation, factory functions, and callbacks.
function counter() {
let count = 0;
return () => ++count;
}
const inc = counter();
console.log(inc()); // 1
console.log(inc()); // 2
What is hoisting in JavaScript?
Hoisting moves declarations to the top of their scope during compilation. var declarations are hoisted and initialized as undefined. Function declarations are fully hoisted. let and const are hoisted but not initialized (temporal dead zone — accessing them before declaration throws ReferenceError).
What is the difference between == and ===?
== performs type coercion before comparison (e.g., "5" == 5 is true). === compares both value and type without coercion ("5" === 5 is false). Always prefer === to avoid unexpected type coercion bugs.
What is the event loop in JavaScript?
The event loop allows JavaScript (single-threaded) to handle async operations. The call stack executes synchronous code. Async callbacks go to the task queue (macrotasks) or microtask queue (Promises). The event loop moves tasks to the call stack when it is empty. Microtasks run before macrotasks.
What is the difference between Promise and async/await?
Both handle asynchronous operations. async/await is syntactic sugar over Promises, making async code look synchronous and easier to read. Error handling uses try/catch instead of .catch().
// Promise
fetch(url).then(r => r.json()).then(data => console.log(data)).catch(console.error);
// async/await
async function getData() {
try {
const r = await fetch(url);
const data = await r.json();
console.log(data);
} catch(e) { console.error(e); }
}
What is prototypal inheritance?
JavaScript objects have a prototype chain. When a property is not found on an object, JavaScript looks up the prototype chain. Objects inherit from Object.prototype by default. ES6 classes are syntactic sugar over prototypal inheritance.
What is the difference between call, apply, and bind?
- call(thisArg, arg1, arg2) — invokes function immediately with given this and individual arguments.
- apply(thisArg, [args]) — invokes function immediately with given this and arguments as array.
- bind(thisArg, arg1) — returns a new function with this permanently bound. Does not invoke immediately.
What is event bubbling and event capturing?
Event bubbling — events propagate from the target element up to the root (default). Event capturing — events propagate from root down to the target. Use addEventListener(event, handler, true) for capturing. stopPropagation() stops propagation.
What is the difference between null and undefined?
undefined means a variable has been declared but not assigned a value. null is an intentional absence of value, explicitly assigned. typeof undefined is "undefined"; typeof null is "object" (a known JavaScript quirk).
What are arrow functions and how do they differ from regular functions?
- Arrow functions do not have their own this — they inherit this from the enclosing scope.
- Arrow functions cannot be used as constructors (no new).
- Arrow functions do not have arguments object.
- Arrow functions are always anonymous.
const add = (a, b) => a + b;
const obj = {
name: "Alice",
greet: function() { return () => this.name; } // arrow inherits this
};
What is destructuring in JavaScript?
Destructuring extracts values from arrays or properties from objects into distinct variables.
const [a, b, ...rest] = [1, 2, 3, 4];
const { name, age = 25 } = { name: "Alice" };
// Function parameter destructuring
function greet({ name, role = "user" }) { return `${name} is ${role}`; }
What is the spread operator and rest parameters?
Spread (...) expands an iterable into individual elements. Rest (...) collects remaining arguments into an array.
const arr = [1, 2, 3];
const copy = [...arr, 4]; // spread: [1,2,3,4]
function sum(...nums) { // rest
return nums.reduce((a, b) => a + b, 0);
}
What is a Promise and what are its states?
A Promise represents an eventual value. States: pending (initial), fulfilled (resolved with value), rejected (failed with reason). Promises are immutable once settled. Use Promise.all(), Promise.race(), Promise.allSettled(), Promise.any() for multiple promises.
What is the difference between map, filter, and reduce?
- map() — transforms each element, returns new array of same length.
- filter() — returns new array with elements that pass a test.
- reduce() — accumulates array into a single value.
const nums = [1,2,3,4,5];
nums.map(x => x * 2); // [2,4,6,8,10]
nums.filter(x => x % 2 === 0); // [2,4]
nums.reduce((acc, x) => acc + x, 0); // 15
What is a WeakMap and WeakSet?
WeakMap and WeakSet hold weak references to objects — they do not prevent garbage collection. WeakMap keys must be objects. Neither is iterable. Useful for storing metadata about objects without memory leaks.
What is the difference between synchronous and asynchronous code?
Synchronous code executes line by line, blocking until each operation completes. Asynchronous code initiates an operation and continues executing other code while waiting for the result (via callbacks, Promises, or async/await).
What are generators in JavaScript?
Generators are functions that can pause and resume execution using yield. They return an iterator. Useful for lazy evaluation, infinite sequences, and async flow control.
function* range(start, end) {
for (let i = start; i <= end; i++) yield i;
}
const gen = range(1, 3);
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
What is the difference between localStorage and sessionStorage?
Both are Web Storage APIs. localStorage persists until explicitly cleared. sessionStorage is cleared when the browser tab is closed. Both store ~5MB of string data and are synchronous.
What is a Symbol in JavaScript?
Symbol is a primitive type that creates unique identifiers. Every Symbol() call returns a unique value. Used as object property keys to avoid name collisions, especially in libraries and frameworks.
What is optional chaining (?.) and nullish coalescing (??)?
- Optional chaining (?.) — safely accesses nested properties without throwing if intermediate value is null/undefined.
- Nullish coalescing (??) — returns right-hand side only when left side is null or undefined (unlike || which also triggers on 0 and "").
const city = user?.address?.city; // no error if address is null
const name = user.name ?? "Anonymous"; // only if null/undefined
What is the difference between deep copy and shallow copy?
Shallow copy copies only the top-level properties; nested objects are still referenced. Deep copy creates completely independent copies of all nested objects. Use structuredClone() or JSON.parse(JSON.stringify()) for deep copy.
What is event delegation?
Event delegation attaches a single event listener to a parent element instead of multiple listeners on children. It uses event bubbling — the parent catches events from children. More efficient for dynamic lists.
document.querySelector("#list").addEventListener("click", (e) => {
if (e.target.matches("li")) console.log(e.target.textContent);
});
What is the difference between Object.freeze() and Object.seal()?
- Object.freeze() — prevents adding, removing, or modifying properties. Object is fully immutable.
- Object.seal() — prevents adding or removing properties, but existing properties can still be modified.