Top 50 JavaScript Interview Questions and Answers (2026)
The 50 JavaScript interview questions that come up most — closures, the event loop, prototypes, async/await, and ES2024 — each with a clear, concise answer.
If you have a JavaScript interview coming up, this guide cuts through the noise and focuses on the questions that actually appear in rounds. Whether you're applying for a frontend, full-stack, or Node.js role, these are the concepts every interviewer reaches for.
JavaScript fundamentals
1. What is the difference between var, let, and const?
var is function-scoped and hoisted (initialized to undefined). let and const are block-scoped and exist in a temporal dead zone until their declaration. const additionally prevents reassignment — but not mutation of objects or arrays.
2. What is hoisting?
Hoisting is JavaScript's behavior of moving variable and function declarations to the top of their scope before code runs. var declarations are hoisted and initialized to undefined; function declarations are fully hoisted (callable before the declaration); let/const are hoisted but not initialized (accessing them throws a ReferenceError).
3. What is the difference between == and ===?
== is the abstract equality operator — it coerces types before comparing (e.g., "5" == 5 is true). === is the strict equality operator — it compares both value and type with no coercion ("5" === 5 is false). Always prefer === unless you intentionally need coercion.
4. What are JavaScript's primitive data types?
There are seven: string, number, bigint, boolean, undefined, null, and symbol. Everything else — arrays, functions, objects — is of type object.
5. Why does typeof null return "object"?
This is a long-standing bug in JavaScript (present since the first version) that was never fixed to avoid breaking the web. null represents the intentional absence of an object, but its internal type tag is 0, which collides with the object tag. Use x === null to check for null explicitly.
6. What values are falsy in JavaScript?
There are exactly six falsy values: false, 0, "" (empty string), null, undefined, and NaN. Every other value — including "0", [], and {} — is truthy.
7. What are template literals and what can they do?
Template literals use backtick (`) syntax and support embedded expressions via ${}, multi-line strings without escape sequences, and tagged templates for custom string processing. They make string composition much cleaner than concatenation.
const name = "Alice";
console.log(`Hello, ${name}! You have ${2 + 3} messages.`);
8. What does the typeof operator return for a function?
typeof returns "function" for callable objects. Functions are technically objects in JavaScript, but the spec gives them their own typeof result to allow easy detection.
9. What is NaN and how do you check for it?
NaN ("Not a Number") is the result of undefined numeric operations like 0 / 0 or parseInt("hello"). Crucially, NaN !== NaN — so never use === to check for it. Use Number.isNaN(x) (strict) rather than the older global isNaN(x) which coerces its argument first.
Functions, scope & closures
10. What is a closure?
A closure is a function that retains access to its outer (lexical) scope even after that outer function has returned.
function makeCounter() {
let count = 0;
return () => ++count;
}
const counter = makeCounter();
counter(); // 1
counter(); // 2
Here count lives in the closure; each call to counter() reads and updates the same variable.
11. What is lexical scope?
Lexical (or static) scope means that the scope of a variable is determined by where it is written in the source code — not where it is called from. JavaScript uses lexical scope for all variable lookups.
12. How does this binding work?
this refers to the object that is the context of a function call. In a method call (obj.fn()), this is obj. In a plain function call (non-strict mode), this is the global object; in strict mode it is undefined. Arrow functions do not have their own this — they inherit it from the enclosing lexical scope.
13. What is the difference between arrow functions and regular functions?
Arrow functions: have no own this (use enclosing scope's), no arguments object, cannot be used as constructors, and have implicit return with a concise body. Regular functions: get their own this on each call, have arguments, and can be new-ed.
14. What is an IIFE?
An Immediately Invoked Function Expression runs as soon as it is defined. It was widely used before modules to create private scope and avoid polluting the global namespace.
(function () {
const privateVar = "hidden";
})();
15. What is currying?
Currying transforms a function that takes multiple arguments into a chain of single-argument functions. add(2)(3) is the curried form of add(2, 3). It enables partial application — fixing some arguments early.
16. Explain the difference between call, apply, and bind.
All three set this explicitly. call(ctx, a, b) invokes immediately with individual args; apply(ctx, [a, b]) invokes immediately with an array; bind(ctx, a) returns a new function with this and optional args pre-bound, without calling it.
17. What is the arguments object?
arguments is an array-like (not a true Array) object available inside non-arrow functions that holds all passed arguments, even those not declared as parameters. Modern code prefers rest parameters (...args) which give a real Array.
Objects & prototypes
18. What is the prototype chain?
Every JavaScript object has an internal [[Prototype]] link (accessible via Object.getPrototypeOf or __proto__). When you access a property, the engine walks up this chain until it finds the property or reaches null. This is how inheritance works in JavaScript.
19. What does Object.create(proto) do?
It creates a new object whose [[Prototype]] is set to proto. This lets you set up prototype chains directly without using new + constructor functions.
const animal = { speak() { return "..."; } };
const dog = Object.create(animal);
dog.speak(); // inherited from animal
20. Is class syntax real class-based inheritance?
No. ES2015 class is syntactic sugar over prototype-based inheritance. Under the hood, class creates a constructor function and sets up prototype chains — there are no Java-style classes.
21. What is the difference between hasOwnProperty and in?
obj.hasOwnProperty("key") returns true only if the property is directly on obj, not inherited. The in operator ("key" in obj) checks the entire prototype chain. Use Object.hasOwn(obj, "key") in modern code (avoids edge cases).
22. What is the difference between a shallow copy and a deep copy?
A shallow copy (e.g., Object.assign({}, obj) or spread {...obj}) copies only top-level properties — nested objects are still shared by reference. A deep copy (e.g., structuredClone(obj) or JSON.parse(JSON.stringify(obj))) recursively copies all levels.
23. What does the new keyword do?
new Fn() creates a fresh object with Fn.prototype as its prototype, sets this to that object inside Fn, and returns the object (unless Fn explicitly returns another object).
Asynchronous JavaScript
24. Explain the JavaScript event loop.
JavaScript is single-threaded. The event loop picks tasks from the task queue and runs them on the call stack one at a time. After each task the engine drains the microtask queue (Promises, queueMicrotask) before picking the next task. This is why Promise.resolve().then(…) always fires before a setTimeout(…, 0).
25. What is the difference between the task queue and the microtask queue?
The task queue (macrotask queue) holds callbacks from setTimeout, setInterval, I/O, and UI events. The microtask queue holds Promise .then/.catch/.finally callbacks and queueMicrotask. Microtasks always drain completely before the next macrotask runs.
26. What is a callback, and what is callback hell?
A callback is a function passed as an argument to be called later — the original async pattern in JavaScript. Callback hell is deeply nested callbacks that make code hard to read and reason about. Promises and async/await solve this.
27. What is a Promise?
A Promise is an object representing the eventual completion (or failure) of an async operation. It has three states: pending, fulfilled, and rejected. You chain .then() for success and .catch() for errors.
28. What does async/await do?
async marks a function as returning a Promise. await pauses execution inside an async function until the awaited Promise settles — but does not block the thread. It makes async code look synchronous and is the preferred style today.
async function fetchUser(id) {
const res = await fetch(`/api/users/${id}`);
const data = await res.json();
return data;
}
29. What is the difference between Promise.all, Promise.race, and Promise.allSettled?
Promise.all([...])— resolves when all promises resolve; rejects as soon as any one rejects.Promise.race([...])— settles (resolve or reject) as soon as the first promise settles.Promise.allSettled([...])— always resolves (never rejects) after all promises settle, giving each outcome individually.
30. How do you handle errors in async/await?
Wrap await calls in a try/catch block. Any rejected Promise will throw inside the async function and be caught there. You can also .catch() on the returned Promise if you prefer.
31. What is Promise.any?
Added in ES2021, Promise.any resolves as soon as any promise in the array fulfills, ignoring rejections. It only rejects if all promises reject, throwing an AggregateError.
ES2015+ & modern JS
32. What is destructuring?
Destructuring lets you unpack values from arrays or properties from objects into variables in a single statement.
const { name, age = 0 } = user; // object destructuring with default
const [first, , third] = items; // array destructuring, skipping second
33. What are spread and rest operators?
Both use ... syntax. Spread expands an iterable into individual elements (useful for copying arrays/objects or passing args). Rest collects remaining elements into an array (in function params or destructuring).
34. What is optional chaining (?.)?
?. short-circuits to undefined if the left side is null or undefined, instead of throwing. user?.address?.city safely navigates nested properties without verbose null checks.
35. What is nullish coalescing (??)?
?? returns the right operand only when the left is null or undefined (unlike || which also triggers on 0, "", false). config.timeout ?? 3000 sets a default without stomping on intentionally-falsy values.
36. What are ES modules?
ES modules (import/export) are the standard module system, supported natively in browsers and Node.js. They are statically analyzed (imports resolved at parse time), always strict, and have their own scope. CommonJS (require/module.exports) is the older Node.js system — dynamic and synchronous.
37. What is the difference between Map and a plain object for key-value storage?
Map accepts any value as a key (not just strings/symbols), preserves insertion order, has a built-in .size, and iterates predictably. Plain objects inherit prototype properties and coerce keys to strings. Use Map when key types vary or order matters.
38. What is Set?
Set is a collection of unique values. It provides O(1) .has(), .add(), .delete(), and iteration. A common use: [...new Set(arr)] to deduplicate an array.
39. What is the difference between for…of and for…in?
for…of iterates over the values of any iterable (arrays, strings, Maps, Sets). for…in iterates over the enumerable property keys of an object, including inherited ones — avoid it for arrays.
40. What are generator functions?
Generator functions (function*) use yield to lazily produce a sequence of values on demand. They return an iterator and pause execution at each yield, resuming when .next() is called — useful for streams, infinite sequences, and custom iteration.
DOM & browser APIs
41. What is event delegation?
Event delegation attaches a single listener to a parent element instead of individual listeners on every child. When a child is clicked, the event bubbles up to the parent where the listener handles it — checking event.target to identify which child triggered it. This is far more efficient for dynamic lists and reduces memory usage.
document.getElementById("list").addEventListener("click", (e) => {
if (e.target.matches("li.item")) {
console.log("Clicked:", e.target.textContent);
}
});
42. What is the difference between stopPropagation and preventDefault?
event.stopPropagation() halts the event from bubbling further up (or capturing further down) the DOM tree. event.preventDefault() cancels the browser's default action for that event (e.g., stopping a form from submitting or a link from navigating) — it does not stop propagation. You can call both together.
43. What is debouncing and how does it differ from throttling?
Debouncing delays executing a function until a specified period of inactivity — if the function is called again before the delay expires, the timer resets. Useful for search-as-you-type (wait until the user stops typing). Throttling ensures a function executes at most once per interval — useful for scroll or resize handlers.
// Debounce: fire 300ms after the last call
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
Advanced objects & immutability
44. What is a Symbol and when would you use one?
Symbol() creates a guaranteed-unique primitive value. Two Symbols are never equal, even with the same description. Common uses: (1) creating private-ish object keys that won't clash with string keys or be accidentally iterated, (2) defining well-known behaviors via built-in Symbols like Symbol.iterator and Symbol.toPrimitive.
45. What is WeakMap and why does it exist?
WeakMap is a key-value store where keys must be objects and are held weakly — if the key object is garbage-collected, its entry is automatically removed. This avoids memory leaks when caching per-object metadata (e.g., attaching private state to a DOM node without preventing GC). Unlike Map, it's not iterable and has no .size.
46. How do you deep-clone an object in JavaScript?
The safest modern approach is structuredClone(obj) (available in Node 17+ and all modern browsers) — it handles nested objects, arrays, Date, Map, Set, and circular references. The older JSON.parse(JSON.stringify(obj)) works for plain data but silently drops undefined, functions, Symbol keys, and Date objects (converting them to strings).
47. What is immutability and how do you achieve it in JavaScript?
Immutability means not mutating existing data — instead, creating new copies with changes applied. It makes state changes predictable and bugs easier to trace. Techniques: Object.freeze(obj) (shallow freeze), spread copies ({ ...obj, key: newVal }), and libraries like Immer for deep immutability. Note: Object.freeze is shallow — nested objects are still mutable.
Useful Array methods
48. What is the difference between map, filter, and reduce?
map(fn)transforms each element and returns a new array of the same length.filter(fn)returns a new array containing only elements for whichfnreturns truthy.reduce(fn, initial)accumulates all elements into a single value — it's the most general of the three (you can implementmapandfilterwithreduce).
const nums = [1, 2, 3, 4, 5];
const doubled = nums.map(n => n * 2); // [2, 4, 6, 8, 10]
const evens = nums.filter(n => n % 2 === 0); // [2, 4]
const total = nums.reduce((acc, n) => acc + n, 0); // 15
49. What does Array.from do?
Array.from(arrayLike, mapFn?) creates a real Array from any iterable or array-like object (one with a .length and numeric indices). Common uses: converting a NodeList to an array, creating a range (Array.from({ length: 5 }, (_, i) => i) → [0, 1, 2, 3, 4]), and spreading a Set into an array while mapping in one step.
50. What is the difference between Array.prototype.find and Array.prototype.findIndex?
find(fn) returns the first element for which fn returns truthy (or undefined if none). findIndex(fn) returns the index of that element (or -1 if not found). Both short-circuit — they stop at the first match. Use find when you need the value; findIndex when you need to splice or replace at that position.
Wrap-up
Mastering these 50 questions gives you a solid foundation for any JavaScript interview — from junior to senior levels. The real advantage comes from being able to explain why things work the way they do, not just recite the answer. Write code, debug closures, break Promises intentionally, and read the spec when something surprises you.