Top 15 JavaScript Interview Questions You Must Know
JavaScript interviews test deep language understanding, not just syntax. Master closures, the event loop, promises, prototypes, and other concepts that interviewers love to ask.
JavaScript is the language of the web, and JavaScript interview questions appear in frontend, full-stack, and even backend (Node.js) interviews. These 15 questions test deep understanding of the language — not just syntax, but how JavaScript actually works under the hood.
1. What are closures?
A closure is a function that retains access to its outer scope's variables even after the outer function has returned.
function createCounter() {
let count = 0;
return {
increment: () => ++count,
getCount: () => count,
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.getCount(); // 2
// 'count' is not accessible directly, but the returned functions can access it
Why it matters: Closures enable data privacy, factory functions, and are fundamental to React hooks.
2. Explain the JavaScript Event Loop
JavaScript is single-threaded but non-blocking. The event loop manages execution:
- Call Stack — Executes synchronous code, one frame at a time
- Microtask Queue — Promises, queueMicrotask (processed after current task, before next task)
- Macrotask Queue — setTimeout, setInterval, I/O (processed one per loop iteration)
console.log('1'); // sync — runs first
setTimeout(() => console.log('2'), 0); // macrotask
Promise.resolve().then(() => console.log('3')); // microtask
console.log('4'); // sync
// Output: 1, 4, 3, 2
3. var vs let vs const
| Feature | var | let | const |
|---|---|---|---|
| Scope | Function | Block | Block |
| Hoisting | Yes (undefined) | Yes (TDZ) | Yes (TDZ) |
| Re-declaration | Allowed | Not allowed | Not allowed |
| Re-assignment | Allowed | Allowed | Not allowed |
Best practice: Use const by default, let when reassignment is needed, never var.
4. How does the "this" keyword work?
- Global context —
window(browser) orglobal(Node) - Object method — The object that owns the method
- Arrow function — Inherits
thisfrom the enclosing scope (lexical binding) - Constructor (new) — The newly created instance
- call/apply/bind — Explicitly set
this
const obj = {
name: 'Alice',
greet() { console.log(this.name); }, // 'Alice'
greetArrow: () => { console.log(this.name); }, // undefined (lexical this)
};
obj.greet(); // 'Alice'
obj.greetArrow(); // undefined
5. Promises and async/await
Promises represent eventual completion or failure of async operations. Three states: pending, fulfilled, rejected.
// Promise chaining
fetch('/api/user')
.then(res => res.json())
.then(user => fetch('/api/posts/' + user.id))
.then(res => res.json())
.catch(err => console.error(err));
// Same thing with async/await (cleaner)
async function getUserPosts() {
try {
const res = await fetch('/api/user');
const user = await res.json();
const postsRes = await fetch('/api/posts/' + user.id);
return await postsRes.json();
} catch (err) {
console.error(err);
}
}
6. How does prototypal inheritance work?
Every JavaScript object has a prototype chain. When you access a property, JS looks up the chain until it finds it or reaches null.
const animal = { speak() { return 'sound'; } };
const dog = Object.create(animal);
dog.bark = () => 'woof';
dog.bark(); // 'woof' (own property)
dog.speak(); // 'sound' (inherited from prototype)
7. Spread and Rest operators
// Spread — expands elements
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }
// Rest — collects elements
function sum(...nums) {
return nums.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3, 4); // 10
8. Destructuring
// Array destructuring
const [first, second, ...rest] = [1, 2, 3, 4, 5];
// Object destructuring with rename and default
const { name: userName, age = 25 } = { name: 'Alice' };
// Nested destructuring
const { address: { city } } = { address: { city: 'Delhi' } };
9. map, filter, and reduce
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 sum = nums.reduce((acc, n) => acc + n, 0); // 15
10. Debounce vs Throttle
Debounce: Wait until the user stops triggering the event, then execute once.
Throttle: Execute at most once per time interval.
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
function throttle(fn, limit) {
let inThrottle = false;
return (...args) => {
if (!inThrottle) {
fn(...args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
11. Deep vs Shallow Copy
Shallow copy copies the top-level properties. Nested objects are still references.
Deep copy recursively copies everything.
// Shallow copy
const shallow = { ...original };
const shallow2 = Object.assign({}, original);
// Deep copy
const deep = structuredClone(original); // Modern API
const deep2 = JSON.parse(JSON.stringify(original)); // Legacy (loses functions, dates)
12. ES Modules vs CommonJS
ES Modules (import/export) — static, tree-shakeable, async loading.
CommonJS (require/module.exports) — dynamic, synchronous, Node.js legacy.
In 2026, ES Modules are the standard everywhere.
13. What are generators?
function* idGenerator() {
let id = 1;
while (true) {
yield id++;
}
}
const gen = idGenerator();
gen.next().value; // 1
gen.next().value; // 2
gen.next().value; // 3
14. WeakMap and WeakSet
Like Map and Set but with weakly held references — keys can be garbage collected when no other references exist. Useful for caching, private data, and avoiding memory leaks.
15. Optional Chaining and Nullish Coalescing
// Optional chaining — safe property access
const city = user?.address?.city; // undefined if any part is null/undefined
// Nullish coalescing — default only for null/undefined (not 0 or '')
const count = data.count ?? 0; // 0 only if data.count is null/undefined
Conclusion
These 15 JavaScript interview questions cover the concepts that interviewers test most frequently. Understanding closures, the event loop, prototypes, and async patterns shows you know JavaScript deeply — not just how to write it, but how it works. Pair this with strong React knowledge for frontend roles, and a solid FAANG preparation plan for the complete package.
Preparing for a JavaScript interview? Try InterviewAlly free and practice with real-time AI-powered coding assistance.