JavaScript interviews at senior level are not about syntax — they are about depth of understanding. These 50 questions cover the concepts that filter senior candidates from mid-level ones: how the event loop actually works, why closures behave the way they do, what this refers to in different contexts, and how memory leaks happen silently. Each answer explains the why, not just the what.
⚡ TL;DR: Senior JS interviews focus on: event loop and async mechanics, closure and scope, prototypal inheritance, this binding rules, memory management, ES6+ features in depth, and performance optimization. Know how V8 works under the hood.
Closures and Scope
// Q1: What is a closure and when would you use one?
// A closure is a function that retains access to its outer scope
// even after the outer function has returned.
function makeCounter(initial = 0) {
let count = initial; // Closed-over variable
return {
increment: () => ++count,
decrement: () => --count,
value: () => count
};
}
const counter = makeCounter(10);
counter.increment(); // 11
counter.value(); // 11
// count is inaccessible from outside — private by closure
// Q2: Classic closure bug in loops
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0); // Prints 3, 3, 3 (not 0, 1, 2)
}
// Fix 1: let (block-scoped, new binding per iteration)
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0); // 0, 1, 2
}
// Fix 2: IIFE to capture value
for (var i = 0; i < 3; i++) {
((j) => setTimeout(() => console.log(j), 0))(i); // 0, 1, 2
}
The Event Loop — Most Common Senior Question
// Q3: What is the output and why?
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
// Output: 1, 4, 3, 2
// Why:
// - 1, 4 = synchronous (call stack)
// - 3 = microtask queue (Promises) — runs BEFORE macrotasks
// - 2 = macrotask queue (setTimeout) — runs after all microtasks
// Q4: What is the difference between microtasks and macrotasks?
// Microtasks: Promise callbacks, queueMicrotask(), MutationObserver
// Macrotasks: setTimeout, setInterval, setImmediate, I/O, UI events
// Microtask queue drains COMPLETELY before next macrotask runs
Prototypal Inheritance
// Q5: How does prototypal inheritance work?
const animal = { breathe() { return 'breathing'; } };
const dog = Object.create(animal);
dog.bark = function() { return 'woof'; };
dog.bark(); // 'woof' — own property
dog.breathe(); // 'breathing' — from prototype chain
// Prototype chain: dog → animal → Object.prototype → null
// Q6: Difference between __proto__, prototype, Object.getPrototypeOf
// __proto__: instance property pointing to prototype (deprecated, use getPrototypeOf)
// .prototype: property on constructor functions only
// Object.getPrototypeOf(obj): correct way to get prototype
function Dog() {}
const d = new Dog();
Object.getPrototypeOf(d) === Dog.prototype; // true
Object.getPrototypeOf(Dog.prototype) === Object.prototype; // true
this Binding Rules
// Q7: What does `this` refer to in each case?
// Rule 1: Default binding — global object (or undefined in strict mode)
function alone() { console.log(this); } // window or undefined
// Rule 2: Implicit binding — the object before the dot
const obj = { name: 'obj', getName() { return this.name; } };
obj.getName(); // 'obj' — this = obj
// Rule 3: Explicit binding — call, apply, bind
function greet(greeting) { return greeting + ' ' + this.name; }
greet.call({ name: 'Alice' }, 'Hello'); // 'Hello Alice'
// Rule 4: Arrow functions — inherit this from enclosing scope
const timer = {
count: 0,
start() {
setInterval(() => this.count++, 1000); // Arrow: this = timer
}
};
// Rule 5: new binding — newly created object
function Person(name) { this.name = name; }
const p = new Person('Bob'); // this inside = new object assigned to p
Hoisting, let/const/var
// Q8: What is hoisting?
// Variables declared with var are hoisted to top of scope and initialized to undefined
// Functions are fully hoisted (declaration + body)
// let/const are hoisted but NOT initialized (Temporal Dead Zone)
console.log(x); // undefined (hoisted)
var x = 5;
console.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 5;
console.log(fn()); // Works! Function declaration fully hoisted
function fn() { return 'hello'; }
console.log(arrow()); // TypeError: arrow is not a function
var arrow = () => 'hello'; // var hoisted as undefined
Memory Leaks
// Q9: Name 4 common JavaScript memory leak patterns
// Leak 1: Global variables
function bad() { leak = 'I am global'; } // Missing var/let/const
// Leak 2: Forgotten event listeners
const el = document.getElementById('btn');
const handler = () => doSomething();
el.addEventListener('click', handler);
// Fix: el.removeEventListener('click', handler) on cleanup
// Leak 3: Closures holding references
function outer() {
const bigData = new Array(1000000);
return () => bigData[0]; // bigData kept alive by closure
}
// Leak 4: Detached DOM nodes
const detached = document.createElement('div');
const map = new Map();
map.set(detached, 'data'); // Map holds reference even if removed from DOM
// Fix: use WeakMap — key is garbage collected when element removed
const wm = new WeakMap();
wm.set(detached, 'data'); // Auto-cleaned when detached is GC'd
Top 15 Quick-Fire Questions with Answers
- Q10: == vs === — == coerces types; === checks type AND value. Always use ===.
- Q11: null vs undefined — undefined = declared but not assigned; null = intentionally empty. typeof null === ‘object’ (historical bug).
- Q12: What is the Temporal Dead Zone? — The period between entering scope and the let/const declaration. Accessing the variable throws ReferenceError.
- Q13: How does Array.prototype.map work? — Creates new array by calling callback on each element. Skips holes in sparse arrays. Returns undefined for missing returns.
- Q14: What is a Promise? — An object representing eventual completion/failure of async operation. States: pending → fulfilled or rejected. Immutable once settled.
- Q15: Difference between call, apply, bind? — call(thisArg, …args): invoke immediately. apply(thisArg, [args]): invoke with array. bind(thisArg): returns new function.
- Q16: What is a Symbol? — Unique primitive. Symbol(‘desc’) !== Symbol(‘desc’). Used for non-enumerable object keys, well-known symbols like Symbol.iterator.
- Q17: WeakMap vs Map? — WeakMap keys must be objects; keys are weakly referenced (GC can collect). Not iterable. Use for private data attached to objects.
- Q18: What is event delegation? — Attaching one listener to parent instead of many to children. Uses event bubbling. More efficient for dynamic lists.
- Q19: Difference between deep and shallow copy? — Shallow: {…obj} copies top-level only, nested objects still reference same memory. Deep: structuredClone() or JSON.parse(JSON.stringify()) creates fully independent copy.
- Q20: What is a generator? — Function* that can pause (yield) and resume. Returns an iterator. Used for lazy evaluation, infinite sequences, and async control flow.
- Q21: What is optional chaining (?.) ? — Short-circuits to undefined if left side is null/undefined. obj?.a?.b?.c avoids nested null checks.
- Q22: What is nullish coalescing (??)? — Returns right side only if left is null or undefined. Unlike ||, does not trigger for 0, ”, or false.
- Q23: How does async/await work internally? — Syntactic sugar over generators + Promises. async function returns a Promise. await pauses function execution, yields control to event loop.
- Q24: What is tree shaking? — Dead code elimination by bundlers (Webpack, Rollup). Requires ES modules (import/export). CommonJS (require) cannot be tree-shaken statically.
These interview concepts connect directly to the async/await patterns guide and the event loop deep dive — knowing the concepts is not enough, you need to know how they affect real production code. External reference: MDN Event Loop documentation.
Recommended Reading
→ Designing Data-Intensive Applications — The essential book every senior developer needs. Covers distributed systems, databases, and production architecture.
→ The Pragmatic Programmer — Timeless engineering wisdom for writing better, more maintainable code at any level.
Affiliate links. We earn a small commission at no extra cost to you.
Free Weekly Newsletter
🚀 Don’t Miss the Next Cheat Code
Join 1,000+ senior developers getting expert-level JS, Python, AWS, system design and AI secrets every week. Zero fluff, pure signal.
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
