OOP Concepts · The Four Pillars

Encapsulation

Encapsulation means an object guards its own data. Other code cannot reach in and break it — it has to ask nicely through methods.

Beginner 5 min Lesson 9 of 38 Runnable examplesExamples use modern JavaScript (ES2022 private fields) and C# 13.
Before you start:Classes and Objects
0/38 in OOP Concepts
On this page · 5 min · Beginner

In simple words#

A medicine capsule keeps the medicine inside and controls how it is released. Encapsulation keeps data inside an object and controls how it changes.

Encapsulation
Bundle data + methods; hide internals.
Getter / setter
Controlled read / write of a field.
Invariant
A rule the object always keeps true (balance ≥ 0).

Learning objectives#

  • Define encapsulation in one sentence
  • Hide state with private fields (#field in JavaScript, private in C#)
  • Validate changes inside methods and setters
  • Explain why encapsulation prevents bugs

Explanation#

Encapsulation bundles data with the methods that operate on it and restricts direct access to that data.

In the previous lesson anyone could write account.balance = -1000000. Encapsulation makes that impossible: balance becomes private, and the only way to change it is through methods that enforce the rules.

JavaScript uses # to mark private fields. C# uses the private keyword plus properties with get and set accessors.

The benefit is control: the class can change how it stores data internally without breaking any code that uses it, and it can never be put into an invalid state.

Visual explanation#

Encapsulation: private state inside the object, public methods on its boundary#balanceprivatedeposit()withdraw()get balance✓ Outside code callspublic methods✕ acc.#balance = 999is a syntax error
Private state lives inside the object; the outside world can only use its public methods.

Code example: Protecting a balance#

JavaScriptProtecting a balance Runnable
class BankAccount {
  #balance = 0;              // private: only code inside the class can touch it


  constructor(owner) {
    this.owner = owner;
  }


  get balance() {            // read-only access from outside
    return this.#balance;
  }


  deposit(amount) {
    if (amount <= 0) throw new Error('Deposit must be positive');
    this.#balance += amount;
  }


  withdraw(amount) {
    if (amount > this.#balance) throw new Error('Insufficient funds');
    this.#balance -= amount;
  }
}


const acc = new BankAccount('Asha');
acc.deposit(1000);
acc.withdraw(300);
console.log('Balance:', acc.balance);


acc.balance = 999999;        // ignored: there is no setter
console.log('Still:', acc.balance);


try {
  acc.withdraw(5000);
} catch (e) {
  console.log('Blocked:', e.message);
}
Expected output
Balance: 700
Still: 700
Blocked: Insufficient funds
Opens this example in the full playground

Step-by-step explanation#

  1. #balance is a private field. Writing acc.#balance outside the class is a syntax error.
  2. get balance() exposes a read-only view of the value.
  3. deposit and withdraw are the only ways to change the balance, and both validate their input.
  4. Assigning acc.balance = 999999 does nothing because the property has a getter but no setter.
  5. An invalid withdrawal throws an error instead of leaving the account negative.

Real-world use case#

An Order class keeps its line items private and exposes addItem() and removeItem(), so the order total is always recalculated correctly and can never drift out of sync.

Common mistakes#

Public fields with no validation

If any code can set user.age = -5, every part of the program has to defend against bad data. Validate once, inside the class.

Getters and setters for everything

Wrapping every field in a trivial get/set adds no protection. Expose behaviour (withdraw) rather than raw data where possible.

Best practices#

  • Make fields private by default
  • Expose intention-revealing methods instead of setters
  • Validate in one place: inside the class
  • Return copies of internal arrays or objects so callers cannot mutate them

Remember this#

Encapsulation = private data, public methods.

Validate once, inside the class.

#field in JavaScript, private in C#.

Practice exercise#

Your task: Create a Temperature class with a private #celsius field. Add a celsius getter, a celsius setter that rejects values below -273.15, and a fahrenheit getter.

Need a hint?
The setter throws for invalid values; fahrenheit is celsius * 9 / 5 + 32.
Show solution
JavaScript Runnable
class Temperature {
  #celsius = 0;
  get celsius() { return this.#celsius; }
  set celsius(value) {
    if (value < -273.15) throw new Error('Below absolute zero');
    this.#celsius = value;
  }
  get fahrenheit() { return this.#celsius * 9 / 5 + 32; }
}
const t = new Temperature();
t.celsius = 25;
console.log(t.fahrenheit); // 77
Opens this example in the full playground

Mini quiz#

Encapsulation quizMultiple choice Question 1 of 3

What is the main goal of encapsulation?

Score so far: 0/0

Want more? Practise all OOP Concepts MCQs · OOP Concepts interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.