Getters and setters let you run code automatically when a property is read or written, while the calling code still uses plain property syntax — no parentheses, no method call. They're defined with the get and set keywords inside a class or object literal, and they're useful whenever you want a property to look simple from the outside but do something smarter underneath, like validation or a computed value.

Getters and Setters in a Class

class Rectangle {
  constructor(width, height) {
    this.width = width;
    this.height = height;
  }

  // A computed property — not stored, calculated on access
  get area() {
    return this.width * this.height;
  }
}

const box = new Rectangle(4, 5);
console.log(box.area); // accessed like a property, not box.area()

Output:

20

Notice box.area is read without parentheses, even though a function runs behind the scenes every time you access it. That's the whole point — it reads exactly like a normal property.

Using a Setter to Validate a Value

A setter runs whenever a property is assigned to, which makes it a natural place to validate or transform incoming values before they're stored.

class User {
  constructor(name) {
    this._name = name; // underscore prefix: the real, internal storage
  }

  get name() {
    return this._name;
  }

  set name(value) {
    if (value.trim().length === 0) {
      throw new Error("Name cannot be empty");
    }
    this._name = value.trim();
  }
}

const u = new User("Sam");
u.name = "  Priya  "; // triggers the setter
console.log(u.name);   // triggers the getter

try {
  u.name = "   "; // fails validation
} catch (err) {
  console.log(err.message);
}

Output:

Priya
Name cannot be empty

The underscore-prefixed _name is just a convention to avoid an infinite loop — if the property were also called name, assigning this.name = value inside the setter would call the setter again, forever.

Getters and Setters in Plain Object Literals

The same syntax works outside classes too:

const temperature = {
  celsius: 0,
  get fahrenheit() {
    return this.celsius * 9 / 5 + 32;
  },
  set fahrenheit(f) {
    this.celsius = (f - 32) * 5 / 9;
  },
};

temperature.celsius = 25;
console.log(temperature.fahrenheit);

Output:

77

Getters and setters pair naturally with everything you already know about JavaScript objects and classes — they don't introduce a new data type, just a way to intercept normal property access with your own logic.