Getters and Setters
A getter runs code when a property is read, and a setter runs code when a property is assigned.
Loading visual…
Definition
A getter, defined with `get propName()`, and a setter, defined with `set propName(value)`, let a property look like a plain field from the outside while actually running a function underneath. Reading `obj.propName` invokes the getter and uses its return value, no parentheses needed, and writing `obj.propName = value` invokes the setter with `value` as its argument instead of just storing it directly. This makes two things possible that a plain property cannot do. A getter can compute a value on the fly from other data, like a `fullName` getter that joins `first` and `last`, so there is nothing to keep in sync. A setter can validate or transform an incoming value before it is stored, like rejecting a negative age, throwing, or clamping it, so invalid state never gets written to the backing field. By convention the real data is kept in a differently named property, often prefixed with an underscore like `_age`, since a setter named `age` that also tries to write directly to `this.age` would call itself again and overflow the call stack.
Examples
class Temperature {
constructor(celsius) {
this.celsius = celsius;
}
get fahrenheit() {
return this.celsius * 9 / 5 + 32;
}
}
new Temperature(20).fahrenheit; // 68, computed on read, no parenthesesfahrenheit is not stored anywhere, the getter recomputes it from celsius every time it is read.
class Account {
#balance = 0;
get balance() {
return this.#balance;
}
set balance(value) {
if (value < 0) throw new Error("Balance cannot be negative");
this.#balance = value;
}
}
const a = new Account();
a.balance = 100; // setter runs, passes validation
a.balance; // 100
a.balance = -5; // throws, #balance stays 100Assigning to balance routes through the setter, which validates the incoming value before touching the private #balance field, so an invalid assignment never changes the stored value.
const obj = {
_name: "Ada",
get name() { return this._name; },
set name(value) { this._name = value.trim(); },
};
obj.name = " Grace ";
obj.name; // "Grace", whitespace trimmed by the setterThe setter transforms the incoming string before storing it, and the getter always reads back the already-cleaned value.
Where you see this
- Validating a value, like rejecting a negative age or an empty username, before it is ever stored.
- Exposing a computed, always-up-to-date value, like a fullName or a total, without a separate field to keep in sync.
- Normalizing input on write, like trimming whitespace or lowercasing an email, so callers cannot forget to do it.
- Guarding a private field so external code can only change it through a validated setter, never directly.