OOP Concepts · Foundations

Access Modifiers

Access modifiers are the locks on your class. They decide which code may see or change each field and method — and they turn encapsulation from a promise into a rule.

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

In simple words#

Rooms in a house: the living room is public, bedrooms are private, and some rooms are only for family (protected). Access modifiers decide who may enter which part of a class.

public
Anyone can use it.
private
Only this class.
protected / internal
Child classes / same project.

Learning objectives#

  • Explain public, private, protected and internal
  • Use #private fields and methods in JavaScript
  • Choose the most restrictive modifier that works
  • Know the JavaScript “_protected” convention

Explanation#

public: anyone can use it. private: only code inside the same class. protected: the class and its subclasses. internal (C#): any code in the same project (assembly).

C# also has protected internal (subclasses OR same project) and private protected (subclasses in the same project). You will rarely need them.

In C#, members are private by default and classes are internal by default.

JavaScript has only two real levels: public, and private with #. A # field or method is invisible outside the class — even to subclasses. There is no protected keyword; developers mark “internal use” members with an underscore (_department), but that is only a convention.

Start private, and open up only when there is a reason. Every public member is a promise you must keep when the class changes.

Syntax#

C# Illustrative
public class Employee
{
    public string Name { get; }          // anyone
    protected string Department { get; }  // this class + subclasses
    internal int BadgeNumber { get; }     // same project
    private decimal _salary;              // this class only


    private decimal TaxRate() => _salary > 50000 ? 0.3m : 0.1m;
}

Code example: Who can see the salary?#

JavaScriptWho can see the salary? Runnable
class Employee {
  #salary;                          // private: only Employee
  _department;                      // "protected" by convention only


  constructor(name, salary, department) {
    this.name = name;               // public
    this.#salary = salary;
    this._department = department;
  }


  get annualSalary() {
    return this.#salary * 12;
  }


  #taxPercent() {                   // private method
    return this.#salary > 50000 ? 30 : 10;
  }


  netMonthly() {
    return (this.#salary * (100 - this.#taxPercent())) / 100;
  }
}


class Manager extends Employee {
  describe() {
    // return this.#salary;         // SyntaxError: #salary is private to Employee
    return `${this.name} manages ${this._department}`;
  }
}


const m = new Manager('Ravi', 80000, 'Sales');
console.log(m.describe());
console.log(m.annualSalary);
console.log(m.netMonthly());
console.log(Object.keys(m));
console.log(m.salary);
Expected output
Ravi manages Sales
960000
56000
[ '_department', 'name' ]
undefined
Opens this example in the full playground

Step-by-step explanation#

  1. #salary and #taxPercent() exist only inside Employee. Even Manager cannot read them.
  2. Public members (name, annualSalary, netMonthly) form the class’s official interface.
  3. _department is public in reality; the underscore only signals “meant for subclasses”.
  4. Object.keys lists only public fields — the private #salary does not appear.
  5. m.salary is undefined: there is no public salary property at all.

Real-world use case#

A payroll library exposes only CalculatePayslip() as public. Tax tables and rounding helpers are private, so the team can change them without breaking any application that uses the library.

Common mistakes#

Making everything public “to be safe”

Public members are hard to change later because other code depends on them. Default to private.

Trusting _underscore as protection

In JavaScript, _department can still be read and changed by anyone. Use # for real privacy.

Using protected for data

Protected fields let every subclass break the base class’s rules. Prefer protected methods over protected fields.

Best practices#

  • Use the most restrictive modifier that works
  • Keep fields private; expose properties or methods
  • Treat public members as a contract
  • Use internal in C# libraries for helpers other projects should not see

Remember this#

public = everyone. private = this class. protected = + children. internal = same project.

JavaScript: # is truly private; _ is just a hint.

Start private, open up only when needed.

Practice exercise#

Your task: Create a PasswordVault class that stores passwords in a private #store Map. Expose save(site, password) and has(site), but no way to read a password back.

Need a hint?
Use this.#store.set(...) and this.#store.has(...).
Show solution
JavaScript Runnable
class PasswordVault {
  #store = new Map();
  save(site, password) { this.#store.set(site, password); }
  has(site) { return this.#store.has(site); }
}
const vault = new PasswordVault();
vault.save('mail', 's3cret');
console.log(vault.has('mail'));   // true
console.log(vault.store);         // undefined
Opens this example in the full playground

Mini quiz#

Access Modifiers quizMultiple choice Question 1 of 3

Which C# modifier lets subclasses use a member but hides it from other code?

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.