~/hackweb.dev
JavaScript Getters, Setters & Encapsulation
Quiz
...

JavaScript Getters, Setters & Encapsulation

beginner · updated Tue Sep 08 2026Contribute

Master encapsulation with getters, setters, and data validation.

JavaScript Getters, Setters & Encapsulation

Control access to object properties and validate data using getters and setters.

Basic Getters and Setters

class Temperature {
  #celsius;

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

  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; }
  set fahrenheit(value) { this.celsius = (value - 32) * 5/9; }
}

let temp = new Temperature(100);
console.log(temp.fahrenheit);  // 212
temp.fahrenheit = 32;
console.log(temp.celsius);     // 0
  • get — Runs when you read the property
  • set — Runs when you assign a value

Validation in Setters

class User {
  #name;
  #email;

  constructor(name, email) { this.name = name; this.email = email; }

  get name() { return this.#name; }
  set name(v) {
    if (!v || v.trim().length < 2) throw new Error("Name too short");
    this.#name = v.trim();
  }

  get email() { return this.#email; }
  set email(v) {
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v)) throw new Error("Invalid email");
    this.#email = v.toLowerCase();
  }
}

let user = new User("John", "[email protected]");
console.log(user.email);  // "[email protected]"

Remember: Setters run on assignment — this.name = "J" triggers the setter.

Computed Properties

Getters calculate values on demand — always in sync:

class Rectangle {
  #w; #h;

  constructor(w, h) { this.w = w; this.h = h; }

  get w() { return this.#w; }
  set w(v) { if (v <= 0) throw new Error("Must be positive"); this.#w = v; }
  get h() { return this.#h; }
  set h(v) { if (v <= 0) throw new Error("Must be positive"); this.#h = v; }

  get area() { return this.#w * this.#h; }
  get isSquare() { return this.#w === this.#h; }
}

let rect = new Rectangle(4, 6);
console.log(rect.area);      // 24
console.log(rect.isSquare);  // false

Tip: Computed properties stay in sync — no need to update them when data changes.

Complete Example: Bank Account

class BankAccount {
  #balance;
  #transactions = [];

  constructor(owner, initialBalance = 0) {
    this.owner = owner;
    this.#balance = initialBalance;
  }

  get balance() { return this.#balance; }
  get transactions() { return [...this.#transactions]; }

  deposit(amount) {
    if (amount <= 0) throw new Error("Amount must be positive");
    this.#balance += amount;
    this.#transactions.push({ type: "deposit", amount });
    return this;
  }

  withdraw(amount) {
    if (amount <= 0) throw new Error("Amount must be positive");
    if (amount > this.#balance) throw new Error("Insufficient funds");
    this.#balance -= amount;
    this.#transactions.push({ type: "withdrawal", amount });
    return this;
  }
}

let account = new BankAccount("John", 1000);
account.deposit(500).withdraw(200);
console.log(account.balance);  // 1300

Remember: transactions returns a copy — external code can’t mutate the internal array.

Best Practices

  • Use getters for computed values — Calculate on demand
  • Use setters for validation — Protect data integrity
  • Use private fields — Encapsulate implementation details
  • Return copies from getters — Prevent external mutation

Common Mistakes

  • Infinite recursion — A getter calling itself
  • Forgetting validation — Invalid data enters the object
  • Mutating returned objects — Return copies instead
  • Not handling null/undefined — Check in setters