What are JavaScript object getters and setters?
The short answer
Getters and setters are special methods that let you define properties which look like regular data properties from the outside, but run a function when you read or write to them. You access them with obj.property syntax — no parentheses — but behind the scenes, a function executes. They're called accessor properties, as opposed to data properties which just store a value.
Think of them as invisible middlemen: the getter runs when you read the property, the setter runs when you assign to it.
The basic syntax
You define getters and setters inside an object literal using the get and set keywords:
const user = {
firstName: 'Alice',
lastName: 'Smith',
get fullName() {
return `${this.firstName} ${this.lastName}`;
},
set fullName(value) {
const parts = value.split(' ');
this.firstName = parts[0];
this.lastName = parts[1];
},
};
console.log(user.fullName); // 'Alice Smith' — getter runs
user.fullName = 'Bob Jones'; // setter runs
console.log(user.firstName); // 'Bob'From the outside, fullName behaves exactly like a regular property. You read it, you assign to it. But underneath, functions are doing the work.
Defining them with Object.defineProperty
You can also add getters and setters to existing objects using Object.defineProperty. This is useful when you want to add accessor properties after an object is created, or when you need control over flags like enumerable and configurable:
const circle = { radius: 5 };
Object.defineProperty(circle, 'area', {
get() {
return Math.PI * this.radius * this.radius;
},
enumerable: true,
configurable: true,
});
console.log(circle.area); // 78.539...How they differ from regular methods
You might wonder: why not just use a getFullName() method? The getter version reads more naturally — user.fullName feels like accessing a property, which it conceptually is. Methods imply doing something. Properties imply reading or writing state. Getters and setters let you keep that distinction while still running logic.
Practical use cases
Validation on assignment
Setters are perfect for enforcing rules when a value is set:
const account = {
_balance: 0,
get balance() {
return this._balance;
},
set balance(amount) {
if (typeof amount !== 'number' || amount < 0) {
throw new Error(
'Balance must be a non-negative number'
);
}
this._balance = amount;
},
};
account.balance = 100; // works
account.balance = -50; // Error: Balance must be a non-negative numberThe setter acts as a gatekeeper. The consuming code just writes account.balance = 100 — the validation happens automatically.
Computed properties
Getters are great for values derived from other data. The result is always in sync because it's computed fresh on every access:
const rect = {
width: 10,
height: 5,
get area() {
return this.width * this.height;
},
};
console.log(rect.area); // 50
rect.width = 20;
console.log(rect.area); // 100 — automatically updatedLazy loading
Sometimes computing a value is expensive. A getter can defer the work and cache the result:
const config = {
_parsedData: null,
rawJson: '{"theme":"dark","lang":"en"}',
get data() {
if (this._parsedData === null) {
this._parsedData = JSON.parse(this.rawJson);
}
return this._parsedData;
},
};
console.log(config.data.theme); // 'dark' — parsed on first access, cached afterLogging and debugging
Setters can also track every change to a property, which is invaluable when debugging mysterious state mutations in your application.
The underscore convention
You'll notice _balance, _count, _parsedData in the examples above. The underscore prefix signals "this is the internal backing store, don't access it directly." JavaScript doesn't enforce this — it's a social contract, not a language feature. If you need true privacy, you can use private class fields with #, closures, or WeakMap-based patterns.
Relationship to property descriptors
Under the hood, getters and setters are part of the property descriptor system. When you inspect an accessor property, its descriptor has get and set instead of value and writable:
const descriptor = Object.getOwnPropertyDescriptor(
user,
'fullName'
);
// { get: [Function], set: [Function], enumerable: true, configurable: true }A property is either a data descriptor (with value and writable) or an accessor descriptor (with get and set). It can never be both — JavaScript throws a TypeError if you try to mix them.
Why interviewers ask this
Getters and setters test whether you understand JavaScript's property model beyond basic key-value pairs. They show up in real codebases for validation, computed values, and backward-compatible API changes — turning a data property into a computed one without changing how callers use it. Interviewers want to know you can leverage the full property system, not just the parts you see in tutorials.