JavaScript Closure & Function Interview Questions (With Answers)
Closures are one of the most asked topics in JavaScript interviews. Almost every interviewer has a favourite closure question, and most of them are output-based.
Before you start, make sure you’ve read the Functions, Higher Order Functions and Closures articles. As always, try to work out each answer yourself before reading the explanation.
1. What is a closure in JavaScript?
Section titled “1. What is a closure in JavaScript?”function createCounter() {
let count = 0;
return function () {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
In the above example, you can see that:
createCounterruns and finishes, so you’d expectcountto be thrown away.- But the inner function still uses
count, so JavaScript keeps it alive. - Every time we call
counter(), it updates that samecount.
A closure is a function that keeps access to the variables from the place where it was written, even after that outer function has finished running.
2. Do two closures from the same function share variables?
Section titled “2. Do two closures from the same function share variables?”function createCounter() {
let count = 0;
return function () {
count++;
return count;
};
}
const counterA = createCounter();
const counterB = createCounter();
console.log(counterA());
console.log(counterA());
console.log(counterB());
Answer: 1, 2, 1
In the above example, you can see that:
- Every call to
createCounter()creates a brand-newcountstarting at0. counterAandcounterBeach remember their owncount.- So calling
counterAtwice doesn’t affectcounterB. It still starts from1.
Remember the car factory from the Closures article? Every car gets its own odometer.
3. Does a closure remember the value or the variable?
Section titled “3. Does a closure remember the value or the variable?”function outer() {
let message = "Hello";
const sayIt = function () {
console.log(message);
};
message = "Bye";
return sayIt;
}
const fn = outer();
fn();
Answer: Bye
Hmm, you may be wondering why it isn’t Hello, since message was "Hello" when sayIt was created.
In the above example, you can see that:
- A closure doesn’t take a snapshot of the value. It keeps a link to the variable itself.
- By the time
sayItactually runs,messagehas already been changed to"Bye". - So it prints whatever is inside the variable at the moment it runs.
4. Why does var in a for loop with setTimeout print the same number?
Section titled “4. Why does var in a for loop with setTimeout print the same number?”for (var i = 1; i <= 3; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
Answer: 4, 4, 4
Wait, what? Shouldn’t it be 1, 2, 3?
In the above example, you can see that:
setTimeoutdoesn’t run its callback right away. The loop finishes first, and the callbacks run later.varis function-scoped, not block-scoped. So there’s only oneishared by the whole loop.- The loop keeps going until
ibecomes4, and then it stops. - A second later, all three callbacks run. They all point to that same
i, which is now4.
Now the fix. Just change var to let:
for (let i = 1; i <= 3; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
// 1, 2, 3
let is block-scoped, so JavaScript creates a new i for every round of the loop. Each callback closes over its own i.
5. Can you call a function before it’s defined in JavaScript?
Section titled “5. Can you call a function before it’s defined in JavaScript?”greet();
sayHi();
function greet() {
console.log("Hello");
}
const sayHi = function () {
console.log("Hi");
};
Answer: Hello, then ReferenceError: Cannot access 'sayHi' before initialization
In the above example, you can see that:
- Remember the Creation Phase from the How JavaScript Works Behind the Scenes article? Before any code runs, JavaScript stores function declarations in memory, with the whole function.
- So
greet()works even though we called it before writing it. sayHiis a function expression stored in aconst. JavaScript knows the variable exists, but it doesn’t get a value until that line actually runs.- Calling it before that line throws a
ReferenceError.
So function declarations can be called before they’re defined, but function expressions and arrow functions can’t.
6. How do you make a function run only once?
Section titled “6. How do you make a function run only once?”This is a classic closure question. Think of a “Pay Now” button. Even if the user clicks it twice, you only want to charge them once.
function once(fn) {
let called = false;
let result;
return function (value) {
if (!called) {
called = true;
result = fn(value);
}
return result;
};
}
function pay(amount) {
console.log(`Paid ₹${amount}`);
return "success";
}
const payOnce = once(pay);
payOnce(500); // Paid ₹500
payOnce(500); // nothing happens
console.log(payOnce(500)); // success
In the above example, you can see that:
onceis a higher order function. It takes a function and returns a new one.- The returned function closes over
calledandresult. - The first call sets
calledtotrueand runspay. - Every call after that skips
payand just returns the savedresult.
7. What is currying in JavaScript? Make sum(1)(2)(3) return 6.
Section titled “7. What is currying in JavaScript? Make sum(1)(2)(3) return 6.”function sum(a) {
return function (b) {
return function (c) {
return a + b + c;
};
};
}
console.log(sum(1)(2)(3)); // 6
In the above example, you can see that:
sum(1)returns a function that remembersaas1.- Calling that with
(2)returns another function that remembers bothaandb. - Calling that with
(3)finally adds all three together.
Currying means turning a function that takes many arguments into a chain of functions that each take one. It works because of closures, since every inner function remembers the values passed before it.
The same thing written with arrow functions looks much shorter:
const sum = (a) => (b) => (c) => a + b + c;
8. What is a higher order function? Write your own map().
Section titled “8. What is a higher order function? Write your own map().”A higher order function is a function that takes another function as an argument, or returns a function, or both.
function myMap(arr, callback) {
const result = [];
for (let i = 0; i < arr.length; i++) {
result.push(callback(arr[i], i));
}
return result;
}
const doubled = myMap([1, 2, 3], (num) => num * 2);
console.log(doubled); // [2, 4, 6]
In the above example, you can see that:
myMaptakes an array and a callback function.- It loops over the array and calls the callback with each item and its index.
- Whatever the callback returns gets pushed into a new array.
- It returns the new array and never touches the original one, just like the real
map().
Pretty neat, right? This question checks whether you understand that map() isn’t magic. It’s just a loop that calls your function.
9. What is an IIFE in JavaScript and why would you use one?
Section titled “9. What is an IIFE in JavaScript and why would you use one?”const counter = (function () {
let count = 0;
return {
increment() {
count++;
return count;
}
};
})();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.count); // undefined
In the above example, you can see that:
- An IIFE (Immediately Invoked Function Expression) is a function that runs as soon as it’s defined. Notice the
()at the very end. - It runs only once and gives back an object with an
incrementmethod. countlives inside the IIFE, so nothing outside can read or change it directly.incrementis a closure, so it’s the only way to updatecount.
People use IIFEs to keep variables private and to avoid filling the global scope with variables.
🧵 Wrapping It Up
Section titled “🧵 Wrapping It Up”You practiced how to:
- Explain closures and predict what they remember
- Solve the famous
varvsletloop question - Tell function declarations from function expressions
- Write
once, a curriedsum, and your ownmap()
Most closure questions are just asking one thing. Which variable does this function remember, and what’s inside that variable when the function actually runs?