Getters and Setters
get/set accessors on objects and classes — computed properties, validation, infinite loop traps, and defineProperty.
- javascript
- getters
- setters
- objects
Getters and setters look like properties but run functions on read/write. Use them for derived values, validation, and lazy init — not for hiding heavy side effects behind innocent obj.foo access.
Object literal syntax
const user = {
first: 'Ada',
last: 'Lovelace',
get fullName() {
return `${this.first} ${this.last}`;
},
set fullName(value) {
const [first, ...rest] = value.split(' ');
this.first = first;
this.last = rest.join(' ');
},
};
user.fullName; // "Ada Lovelace"
user.fullName = 'Grace Hopper';
user.first; // "Grace"
Classes
class Celsius {
#c = 0;
constructor(c) {
this.c = c;
}
get c() {
return this.#c;
}
set c(n) {
if (typeof n !== 'number' || Number.isNaN(n)) {
throw new TypeError('expected number');
}
this.#c = n;
}
get f() {
return this.#c * 1.8 + 32;
}
set f(v) {
this.c = (v - 32) / 1.8;
}
}
const t = new Celsius(0);
t.f; // 32
t.f = 212;
t.c; // 100
Infinite recursion trap
const bad = {
get x() {
return this.x; // stack overflow — calls itself
},
set x(v) {
this.x = v; // same problem
},
};
Store in a different field (_x, #x, or a WeakMap).
defineProperty
const obj = { _n: 0 };
Object.defineProperty(obj, 'n', {
enumerable: true,
configurable: true,
get() {
return this._n;
},
set(v) {
this._n = Number(v) || 0;
},
});
Accessors from defineProperty can be non-enumerable — useful for libraries.
When getters hurt
const report = {
get rows() {
return expensiveQuery(); // runs every read
},
};
// console.log(report.rows, report.rows) → twice the cost
Readers assume property access is cheap. For expensive work, use a method getRows() or memoize explicitly.
get rows() {
if (!this._rows) this._rows = expensiveQuery();
return this._rows;
}
Invalidate _rows when inputs change.
Serialization
JSON.stringify({
get x() {
return 1;
},
});
// '{"x":1}' — getter is invoked
// setters don't participate in stringify
Object.assign and spread invoke getters and copy values (not the accessor):
const copy = { ...user }; // fullName becomes a data property string
Interview answer
“Getters and setters are accessor properties that run code on get/set. I use them for derived fields and validation with a separate backing store to avoid recursion. I avoid heavy side effects in getters because they look like cheap fields. Spread and JSON.stringify invoke getters and snapshot values.”
Related
Proxy vs accessors
Accessors are fixed per property. A Proxy traps all gets/sets dynamically (validation frameworks, reactive systems). Prefer explicit getters for known derived fields; reach for Proxy when the key set is open-ended.
const bag = {
_values: new Map(),
get(key) {
return this._values.get(key); // method, not accessor
},
};
// don't pretend dynamic keys are accessors without Proxy
In React, derived values are usually plain expressions in render or useMemo, not OOP getters on state objects — different style, same idea: compute from source fields without storing duplicates that go stale.
enumerable and tooling
Object.defineProperty(obj, 'total', {
enumerable: true,
get() {
return this.price * this.qty;
},
});
Non-enumerable accessors hide from Object.keys and spread — useful for internal caches, confusing if you expected them in logs. Debuggers show getters as properties; beware evaluating a throwing getter while hovering in DevTools.
Further reading
Related guides
- Destructuring Objects and ArraysObject and array destructuring — renames, defaults, nested patterns, rest, and parameter destructuring in real APIs.
- Prototypal InheritanceHow JS objects delegate via [[Prototype]] — chains, Object.create, constructors, classes as sugar, own vs inherited props, and common footguns.
- AbortControllerCancel fetch and other async work with AbortController and AbortSignal — timeouts, race conditions, and cleanup when components unmount.
- Array find, some, every, includesShort-circuiting array predicates: find, findIndex, some, every, and includes — when to use each and common interview traps.
- Array map, filter, reducemap, filter, and reduce as the core transform toolkit — immutability, chaining costs, reduce patterns, and when a plain loop is clearer.