Using closures for private variables

JavaScript

The short answer

JavaScript does not have a built-in private keyword like Java or C++. But closures give you a way to create variables that cannot be accessed from outside a function. The trick is simple — define a variable inside a function and return inner functions that use it. The variable stays alive through the closure, but nobody outside can touch it directly.

How it works

When a function returns another function, the returned function keeps access to the variables from the outer function. But those variables are not accessible from anywhere else.

function createCounter() {
let count = 0;
return {
increment() {
count += 1;
return count;
},
decrement() {
count -= 1;
return count;
},
getCount() {
return count;
},
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.getCount(); // 2
// There is no way to access count directly
console.log(counter.count); // undefined

The variable count is private. The only way to interact with it is through the increment, decrement, and getCount methods. You cannot read it, change it, or reset it from outside unless the returned methods allow it.

A practical example — user authentication

Here is a more real-world example. Imagine you are building a simple authentication module:

function createAuth() {
let token = null;
let currentUser = null;
return {
login(user, authToken) {
currentUser = user;
token = authToken;
},
logout() {
currentUser = null;
token = null;
},
getUser() {
return currentUser;
},
isLoggedIn() {
return token !== null;
},
};
}
const auth = createAuth();
auth.login({ name: 'John' }, 'abc123');
auth.isLoggedIn(); // true
auth.getUser(); // { name: "John" }
// The token is private — nobody can steal it
console.log(auth.token); // undefined

The token is hidden. No external code can read or modify it. This is data privacy through closures.

Factory functions vs classes

You might wonder — "Can't I just use a class with #private fields?" Yes, you can. Modern JavaScript has private class fields:

class Counter {
#count = 0;
increment() {
this.#count += 1;
return this.#count;
}
}

The #count field is truly private. Both approaches work, but closures have been used for much longer and you will see them everywhere in older codebases. Closures also work in factory functions, which do not need the new keyword and do not deal with this.

Common patterns

Module pattern — one of the most popular uses of closures for privacy:

const logger = (function () {
const logs = [];
return {
add(message) {
logs.push({ message, timestamp: Date.now() });
},
print() {
logs.forEach((log) => console.log(log.message));
},
count() {
return logs.length;
},
};
})();
logger.add('App started');
logger.add('User logged in');
logger.count(); // 2
logger.print(); // "App started", "User logged in"
// logs array is completely hidden
console.log(logger.logs); // undefined

The IIFE (Immediately Invoked Function Expression) runs once and returns an object with methods. The logs array is private — no one can clear it, modify it, or access it directly.

Interview Tip

If the interviewer asks about private variables in JavaScript, start with closures because they are the traditional approach and work everywhere. Then mention #private class fields as the modern alternative. Show a practical example like the counter or auth module to demonstrate the concept. The key point is that the variable is not on the returned object — it lives in the closure scope.

Why interviewers ask this

This question tests two things at once — your understanding of closures and your understanding of data encapsulation. Interviewers want to see if you know how to hide implementation details and expose only what is necessary. This is a fundamental principle of good software design, and being able to do it in JavaScript (which lacks traditional access modifiers) shows you understand the language deeply.