Using closures for private variables
JavaScriptThe 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(); // 1counter.increment(); // 2counter.getCount(); // 2// There is no way to access count directlyconsole.log(counter.count); // undefinedThe 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(); // trueauth.getUser(); // { name: "John" }// The token is private — nobody can steal itconsole.log(auth.token); // undefinedThe 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(); // 2logger.print(); // "App started", "User logged in"// logs array is completely hiddenconsole.log(logger.logs); // undefinedThe 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.