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.

Using Getters
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.

Using Setters
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.

defineProperty with Accessors
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.

defineProperties()
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.

AttributeData PropertyAccessor PropertyDefault
valueYesNoundefined
writableYesNofalse
getNoYesundefined
setNoYesundefined
enumerableYesYesfalse
configurableYesYesfalse
Reading Property Descriptors
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);
📝 Note: Getters and setters provide a way to intercept property access and assignment. They are commonly used for data validation, computed properties, and backward compatibility when changing how a property works internally. The convention of prefixing private properties with _ (e.g., _radius) is just a naming convention; these properties are still accessible.
Exercise:
How do you access a getter property?
Try it YourselfCtrl+Enter to run
Click Run to see the output here.