If you are learning Object-Oriented Programming (OOP) in JavaScript, one word that starts appearing very often is: Encapsulation
At first, it can sound like a big and confusing concept.
When I started learning it, I realized the idea is actually much simpler than the name.
Encapsulation is mainly about protecting data and controlling how that data is used.
In simple words, it helps us stop objects from being changed in the wrong way.
In this post, let’s understand encapsulation in JavaScript in the simplest way possible.
🧠 What Is Encapsulation?
Encapsulation means:
- keeping data and methods together inside a class
- hiding internal details from the outside world
- allowing access through controlled methods
In simple words:
The object should control its own data.
For example, if we have a bank account, its balance should not be changed randomly from outside.
Doing this is risky:
account.balance = -5000;
Instead, we should allow safe actions like:
account.deposit(1000);
account.withdraw(500);
That is the core idea of encapsulation.
🔒 Why Do We Need Encapsulation?
Without encapsulation, any part of the program can directly change important values.
That can create invalid states and bugs.
For example:
- a bank balance should not become negative randomly
- marks should not go above 100
- product price should not become negative
- salary should not go below 0
Encapsulation helps us protect these values by making sure updates happen only in valid ways.
It also makes code cleaner and easier to maintain.
📦 Real-Life Analogy
Think of an ATM.
When you use an ATM, you do not open the machine and directly edit its internal data.
You only interact with the options it gives you:
- check balance
- deposit
- withdraw
The internal working stays hidden.
You only use the allowed interface.
That is a simple real-world example of encapsulation.
⚙️ How Encapsulation Works in JavaScript
In JavaScript, one common way to achieve encapsulation is by using:
- private fields
- public methods
Private fields are written using #.
Example:
#balance
This means that field can only be accessed inside the class.
Code outside the class cannot use it directly.
🏦 BankAccount Example
Let’s understand this with a simple example.
class BankAccount {
#accountHolderName;
#balance;
constructor(accountHolderName, balance) {
this.#accountHolderName = accountHolderName;
this.#balance = balance > 0 ? balance : 0;
}
getAccountHolderName() {
return this.#accountHolderName;
}
getBalance() {
return this.#balance;
}
deposit(amount) {
if (amount <= 0) {
console.log("Deposit amount must be positive.");
return;
}
this.#balance += amount;
}
withdraw(amount) {
if (amount <= 0) {
console.log("Withdrawal amount must be positive.");
return;
}
if (amount > this.#balance) {
console.log("Insufficient funds.");
return;
}
this.#balance -= amount;
}
}
const account = new BankAccount("Saurav", 5000);
console.log(account.getBalance()); // 5000
account.deposit(1000);
console.log(account.getBalance()); // 6000
account.withdraw(2000);
console.log(account.getBalance()); // 4000
🔍 What Is Happening Here?
Let’s break it down.
1. #accountHolderName and #balance are private fields
#accountHolderName;
#balance;
These values are hidden from outside code.
That means this is not allowed:
account.#balance = 100000; // Error
Only the class itself can access and change #balance.
2. The constructor sets the initial values
constructor(accountHolderName, balance) {
this.#accountHolderName = accountHolderName;
this.#balance = balance > 0 ? balance : 0;
}
When the object is created, the constructor initializes the private data.
We also added a small validation so invalid starting balance becomes 0.
3. getBalance() gives controlled read access
getBalance() {
return this.#balance;
}
If we want the balance, we ask the object for it.
We do not access it directly.
4. deposit() and withdraw() control updates
These methods decide how balance can change.
For example:
- deposit must be positive
- withdrawal must be positive
- withdrawal cannot be more than current balance
This is where encapsulation becomes useful.
Instead of letting outside code change the balance however it wants, the object protects its own state.
❌ Without Encapsulation vs ✅ With Encapsulation
Without encapsulation
class BankAccount {
constructor(name, balance) {
this.name = name;
this.balance = balance;
}
}
const account = new BankAccount("Saurav", 5000);
account.balance = -10000;
console.log(account.balance); // -10000
This is dangerous because anyone can change the balance directly.
With encapsulation
class BankAccount {
#balance;
constructor(balance) {
this.#balance = balance;
}
getBalance() {
return this.#balance;
}
withdraw(amount) {
if (amount > 0 && amount <= this.#balance) {
this.#balance -= amount;
}
}
}
Now the balance is protected.
That is much safer.
🧩 A Common Beginner Mistake
One very common mistake in JavaScript is confusing these two:
this.#balance
this.balance
They are not the same thing.
-
this.#balance→ private field -
this.balance→ normal public property
If your class uses #balance, then inside the class you must always use this.#balance.
If you accidentally write this.balance, you are working with a different property.
That can create confusing bugs.
🎯 Getters and Setters
Encapsulation is often explained using getters and setters.
Here is a simple example:
class Student {
#marks;
constructor(marks) {
this.#marks = marks >= 0 && marks <= 100 ? marks : 0;
}
getMarks() {
return this.#marks;
}
setMarks(newMarks) {
if (newMarks >= 0 && newMarks <= 100) {
this.#marks = newMarks;
} else {
console.log("Invalid marks");
}
}
}
const s1 = new Student(80);
console.log(s1.getMarks()); // 80
s1.setMarks(95);
console.log(s1.getMarks()); // 95
s1.setMarks(150); // Invalid marks
Here:
-
#marksis private -
getMarks()reads the value -
setMarks()updates it with validation
This is a common encapsulation pattern.
🛠️ Business Methods Are Often Better Than Generic Setters
In real-world code, generic setters are not always the best choice.
For example, instead of writing this:
setBalance(amount)
it is often better to write:
deposit(amount)
withdraw(amount)
transfer(amount)
Why?
Because these methods reflect real actions.
They also make business rules clearer.
For a bank account, deposit() and withdraw() are more meaningful than a plain setBalance().
That is why encapsulation is not only about private variables.
It is also about controlled behavior.
✅ Benefits of Encapsulation
Here are some practical benefits:
1. Better data protection
Important values stay safe from direct misuse.
2. Better validation
You can stop invalid updates before they happen.
3. Cleaner code
The logic related to one object stays inside that object.
4. Easier maintenance
You can change internal implementation later without affecting outside code too much.
5. Better interview understanding
Encapsulation is one of the most important OOP concepts asked in interviews.
⚠️ Common Beginner Mistakes
1. Making everything public
If everything is public, outside code can change object state freely.
2. Using setters without validation
If setters accept invalid data, encapsulation becomes weak.
3. Thinking encapsulation only means private variables
Private fields are one part of it, but the bigger idea is controlled access.
4. Mixing this.balance and this.#balance
This is one of the easiest mistakes to make in JavaScript.
🎤 How to Explain Encapsulation in an Interview
If someone asks:
What is encapsulation?
You can say:
Encapsulation is the process of bundling data and methods together inside a class and restricting direct access to internal state. It helps protect data and allows controlled access through methods.
How do you achieve encapsulation in JavaScript?
You can say:
In JavaScript, encapsulation can be achieved using private fields like
#balanceand public methods like getters, setters, or business methods such asdeposit()andwithdraw().
Why is encapsulation useful?
You can say:
Encapsulation helps protect object data, prevents invalid state changes, and makes code cleaner and easier to maintain.
🚀 Final Thoughts
Encapsulation may sound like a difficult OOP term at first.
But the idea is actually simple.
It means:
- keep data and methods together
- hide internal details when needed
- allow controlled access through methods
If you are learning OOP in JavaScript, start with small examples like:
- student marks
- product price
- employee salary
- bank account
Once these examples become clear, encapsulation starts feeling natural.
And after that, learning concepts like inheritance, polymorphism, and abstraction becomes much easier.
🙋♂️ About Me
Hi, I’m Saurav Kumar.
I enjoy learning, building, and writing about web development in simple words—especially breaking down topics that are useful for beginners and developers preparing for interviews.
Right now, I’m focusing on deepening my understanding of core concepts like JavaScript, Object-Oriented Programming, system design, and software engineering fundamentals.
Let's connect!
- 🐙 GitHub: @saurav02022
- 💼 LinkedIn: Saurav Kumar
Top comments (0)