Facebook Pixel

Closures Deep Dive: Interview Questions in JavaScript

Advanced closure interview questions covering data hiding, constructors, GC, and tricky patterns.

Closures Deep Dive: Interview Questions in JavaScript

Advanced closure interview questions go beyond the basics. Here are the tricky ones with answers.

Q1: What is the output?

function createFunctions() { const result = []; for (var i = 0; i < 3; i++) { result.push(function () { return i; }); } return result; } const fns = createFunctions(); console.log(fns.map(f => f())); `` **Answer**: `[3, 3, 3]`. All closures share one `i` (var). Fix with `let`. ### Q2: Implement a function that can only be called once. ```js function once(fn) { let done = false; let result; return (...args) => { if (done) return result; done = true; result = fn(...args); return result; }; } `` ### Q3: Implement a memoize function. ```js function memoize(fn) { const cache = {}; return (...args) => { const key = JSON.stringify(args); if (!(key in cache)) cache[key] = fn(...args); return cache[key]; }; } `` ### Q4: What is the output? ```js function counter() { let count = 0; return { increment: () => ++count, getCount: () => count, }; } const c = counter(); const { increment, getCount } = c; increment(); increment(); console.log(getCount()); `` **Answer**: `2`. Both `increment` and `getCount` close over the same `count`. Destructuring does not break the closure. ### Q5: Implement a debounce function. ```js function debounce(fn, delay) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), delay); }; } `` ### Q6: Implement a throttle function. ```js function throttle(fn, delay) { let last = 0; return (...args) => { const now = Date.now(); if (now - last >= delay) { last = now; fn(...args); } }; } `` ### Q7: What is the output? ```js function makeAdder(x) { return function (y) { return function (z) { return x + y + z; }; }; } const add5 = makeAdder(5); const add5and3 = add5(3); console.log(add5and3(2)); // 10 `` **Answer**: `10`. Each nested function closes over its parent's variables. `x=5`, `y=3`, `z=2` -> `5+3+2=10`. ### Q8: Explain closures and data hiding with an example. ```js function createUser(name) { let password = "secret"; return { getName: () => name, authenticate: (pwd) => pwd === password, }; } const user = createUser("Kunal"); user.password; // undefined (hidden) user.authenticate("secret"); // true `` `password` is private. Only `authenticate` can check it. ### Q9: What is a memory leak caused by closures? Give an example. ```js const handlers = []; function setup() { const big = new Array(1_000_000); handlers.push(() => big.length); } setup(); // big stays alive because the handler closes over it `` Fix: remove the handler when done, or extract only what you need. ### Q10: How do closures work with `this`? Regular functions: `this` is determined at call time, so a closure does not capture `this` (unless the closure is an arrow function). Arrow functions: `this` is lexical, so the arrow captures `this` from the enclosing scope. ### The Takeaway Advanced closure questions test: the loop bug (var vs let), utility functions (once, memoize, debounce, throttle), nested closures, data hiding, memory leaks, and closures + `this`. Practice implementing each utility from scratch and explaining the lexical environment that makes it work.

Create a cache object in the outer function. Return a function that serializes the arguments as a key, checks the cache, and either returns the cached result or calls the original function and stores the result. The cache is private to the closure.

Close over a timer variable. Each call clears the previous timer and sets a new one. The function only runs after the user stops calling for the specified delay. The timer persists across calls via the closure.

No. Destructuring methods from a closure-based object (const { increment, getCount } = c) still close over the same private variables. Both increment and getCount access the same count. The closure is not broken.

Each nested function closes over its parent's variables. So makeAdder(5)(3)(2) works because the innermost function can access x (from the outermost), y (from the middle), and z (its own parameter). The scope chain connects all of them.

Regular functions do not capture this in a closure; this is determined at call time. Arrow functions capture this lexically from the enclosing scope, so an arrow inside a method preserves the method's this. This is why arrows fix the this-in-callback bug.

Ready to master React completely?

Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.

Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.