JavaScript Object Accessors
Object accessors (getters and setters) allow you to define computed properties on objects. Getters return a computed value when a property is accessed, and setters run code when a property is assigned a value.
The get Keyword
A getter is defined using the get keyword. It looks like a property but is actually a function that runs when the property is accessed. Getters are useful for computed or derived values.
const person = {
firstName: 'Alice',
lastName: 'Smith',
// Getter: accessed like a property, not a method
get fullName() {
return this.firstName + ' ' + this.lastName;
}
};
// Access as property (no parentheses!)
console.log(person.fullName);
person.firstName = 'Bob';
console.log(person.fullName);The set Keyword
A setter is defined using the set keyword. It runs when a value is assigned to the property. Setters are useful for validation, formatting, or triggering side effects on assignment.
const temperature = {
_celsius: 0,
get fahrenheit() {
return this._celsius * 9/5 + 32;
},
set fahrenheit(value) {
this._celsius = (value - 32) * 5/9;
},
get celsius() {
return this._celsius;
},
set celsius(value) {
if (value < -273.15) {
console.log('Invalid: below absolute zero!');
return;
}
this._celsius = value;
}
};
temperature.celsius = 100;
console.log('Celsius: ' + temperature.celsius);
console.log('Fahrenheit: ' + temperature.fahrenheit);
temperature.fahrenheit = 32;
console.log('Celsius: ' + temperature.celsius);
temperature.celsius = -300;Object.defineProperty()
Object.defineProperty() allows you to add or modify properties with fine-grained control over their behavior, including getters, setters, and property descriptors.
const user = { firstName: 'Alice', lastName: 'Smith' };
// Define a getter/setter with defineProperty
Object.defineProperty(user, 'fullName', {
get: function() {
return this.firstName + ' ' + this.lastName;
},
set: function(value) {
const parts = value.split(' ');
this.firstName = parts[0];
this.lastName = parts[1] || '';
},
configurable: true,
enumerable: true
});
console.log(user.fullName);
user.fullName = 'Bob Jones';
console.log(user.firstName);
console.log(user.lastName);Object.defineProperties()
Object.defineProperties() lets you define multiple properties at once, each with its own descriptor including getters, setters, and attribute flags.
const circle = {};
Object.defineProperties(circle, {
_radius: {
value: 5,
writable: true,
enumerable: false
},
radius: {
get: function() { return this._radius; },
set: function(r) {
if (r < 0) throw new Error('Radius must be positive');
this._radius = r;
},
enumerable: true,
configurable: true
},
area: {
get: function() {
return Math.PI * this._radius * this._radius;
},
enumerable: true
}
});
console.log('Radius: ' + circle.radius);
console.log('Area: ' + circle.area.toFixed(2));
circle.radius = 10;
console.log('New area: ' + circle.area.toFixed(2));Property Descriptors
Every property has a descriptor that controls its behavior. Data properties have value and writable, while accessor properties have get and set. Both types have enumerable and configurable.
| Attribute | Data Property | Accessor Property | Default |
|---|---|---|---|
| value | Yes | No | undefined |
| writable | Yes | No | false |
| get | No | Yes | undefined |
| set | No | Yes | undefined |
| enumerable | Yes | Yes | false |
| configurable | Yes | Yes | false |
const obj = {};
Object.defineProperty(obj, 'name', {
value: 'Alice',
writable: false,
enumerable: true,
configurable: false
});
const desc = Object.getOwnPropertyDescriptor(obj, 'name');
console.log('value: ' + desc.value);
console.log('writable: ' + desc.writable);
console.log('enumerable: ' + desc.enumerable);
console.log('configurable: ' + desc.configurable);
// Trying to modify a non-writable property
obj.name = 'Bob';
console.log('After assignment: ' + obj.name);