Last modified: May 14, 2026 By Alexander Williams
JavaScript Private Variables Guide
What Are Private Variables?
Private variables are data that cannot be accessed from outside a function or object. They help keep your code secure and organized. In JavaScript, we use closures, classes, or modules to create them.
Unlike public variables, private ones are hidden. This prevents accidental changes. It also makes your code easier to debug. Understanding types of JavaScript variables is a good first step.
Why Use Private Variables?
Private variables protect sensitive data. They also reduce naming conflicts. When you hide internal state, you control how data changes. This is called encapsulation.
Encapsulation improves code maintainability. It also makes your code more predictable. For example, you can validate data before storing it. This prevents bugs.
Using Closures for Privacy
Closures are the oldest way to create private variables. A closure is a function that remembers its outer scope. You can define a variable inside a function and return inner functions that access it.
Here is a simple example:
function createCounter() {
// This variable is private
let count = 0;
return {
increment: function() {
count++;
console.log('Count is now ' + count);
},
decrement: function() {
count--;
console.log('Count is now ' + count);
},
getCount: function() {
return count;
}
};
}
const myCounter = createCounter();
myCounter.increment(); // Count is now 1
myCounter.increment(); // Count is now 2
console.log(myCounter.getCount()); // 2
// Cannot access count directly
console.log(myCounter.count); // undefined
Notice that count is not accessible outside createCounter. The returned object has methods that work with count. This keeps the variable private.
Private Variables with Classes
Modern JavaScript uses the # syntax for private fields. This works in classes. It is cleaner and easier to read. The # makes the field truly private.
Here is an example using a class:
class BankAccount {
// Private field
#balance = 0;
constructor(initialBalance) {
this.#balance = initialBalance;
}
deposit(amount) {
if (amount > 0) {
this.#balance += amount;
console.log('Deposited ' + amount);
}
}
withdraw(amount) {
if (amount > 0 && amount <= this.#balance) {
this.#balance -= amount;
console.log('Withdrew ' + amount);
}
}
getBalance() {
return this.#balance;
}
}
const account = new BankAccount(100);
account.deposit(50); // Deposited 50
account.withdraw(30); // Withdrew 30
console.log(account.getBalance()); // 120
// Cannot access #balance directly
console.log(account.#balance); // SyntaxError
The #balance field is private. It cannot be accessed outside the class. This is a strong encapsulation mechanism. It works in modern browsers and Node.js.
Private Variables with IIFE
An IIFE (Immediately Invoked Function Expression) can also create private variables. This pattern is common in older code. It runs once and returns an object with methods.
Example using IIFE:
const person = (function() {
// Private variable
let name = 'John';
let age = 30;
return {
setName: function(newName) {
name = newName;
},
setAge: function(newAge) {
if (newAge > 0) {
age = newAge;
}
},
getInfo: function() {
return name + ' is ' + age + ' years old.';
}
};
})();
console.log(person.getInfo()); // John is 30 years old.
person.setName('Jane');
person.setAge(25);
console.log(person.getInfo()); // Jane is 25 years old.
// Cannot access name or age
console.log(person.name); // undefined
The IIFE creates a private scope. The variables name and age are only accessible through the returned methods. This is a classic module pattern.
Private Variables in Modules
JavaScript modules have their own scope. Variables declared in a module are private by default. You export only what you want to share. This is the modern way to organize code.
Example module file counter.js:
// counter.js
let count = 0; // Private to this module
export function increment() {
count++;
console.log('Count is ' + count);
}
export function decrement() {
count--;
console.log('Count is ' + count);
}
export function getCount() {
return count;
}
Then import in another file:
// app.js
import { increment, getCount } from './counter.js';
increment(); // Count is 1
increment(); // Count is 2
console.log(getCount()); // 2
// count is not accessible here
Module scope is a natural way to create private variables. It works without extra syntax. This is the recommended approach for larger projects.
Private Variables with WeakMap
Another technique uses WeakMap. This is useful for older JavaScript versions. It stores private data for each object instance.
Example using WeakMap:
const privateData = new WeakMap();
class User {
constructor(name, email) {
privateData.set(this, { name, email });
}
getName() {
return privateData.get(this).name;
}
getEmail() {
return privateData.get(this).email;
}
}
const user1 = new User('Alice', '[email protected]');
console.log(user1.getName()); // Alice
console.log(user1.getEmail()); // [email protected]
// Cannot access private data directly
console.log(privateData.get(user1)); // { name: 'Alice', email: '[email protected]' }
WeakMap holds the private data. It is not accessible from outside. This method is less common but still useful. It works in environments without private class fields.
Common Mistakes to Avoid
One mistake is thinking that _ prefix makes a variable private. In JavaScript, underscore is just a naming convention. It does not enforce privacy. Developers can still access it.
Another mistake is using global variables for private data. This breaks encapsulation. Always use closures, classes, or modules.
Also, remember that private class fields with # are not supported in all environments. Check your target browsers before using them.
Performance Considerations
Private variables with closures have a small memory cost. Each closure creates a new scope. For most applications, this is negligible.
Private class fields with # are optimized by modern engines. They are as fast as public fields. Use them when possible.
Modules are very efficient. They create scope once at load time. This is the best choice for performance.
When to Use Each Method
Use closures for simple functions or when supporting older browsers. Use private class fields for new projects with modern JavaScript. Use modules for reusable code that needs privacy across files.
Use WeakMap only when you cannot use private fields. It is a fallback solution. For most cases, class fields or modules are best.
Understanding JavaScript variable scope helps you choose the right method. Scope determines where variables are accessible.
Conclusion
Private variables are essential for clean and secure JavaScript code. They prevent accidental data changes and reduce bugs. You can create them with closures, classes, modules, or WeakMap.
Start with closures or private class fields. They are easy to understand and widely supported. For larger projects, use modules. They provide natural privacy.
Practice with examples to build your skills. Encapsulation makes your code more professional. It also helps you work in teams. Remember to check JavaScript variable declaration rules before starting.
Now you know how to keep your data safe. Use private variables in your next project. Your code will be more robust and maintainable.