JS Tip of the Day: Accessor Properties (Getter/Setter)

Accessor Properties (Getter/Setter)
Level: Intermediate

There are two kinds of properties in JavaScript, data properties and accessor properties. Data properties are your normal, every-day properties with no special behavior (unless exotic, I’m looking at you array length). They’re often defined using the = operator (or : in object literals) and are easily accessed by name through the . or [] operators.

Accessor properties work the same way on the outside, but internally each time you access or assign a value using an accessor property, a function gets executed. The access function is called a “getter” while the assignment function is called a “setter” and they’re responsible for providing or assigning the value of that property. Because of this, you may hear accessor properties referred to as “getter-setter” properties.

You can create accessor properties in object literals and classes using the get and set keywords before your method names. Instead of becoming a method callable as a function, the method instead becomes an accessor property. Getter methods should be defined without parameters while setter methods should be defined with a single parameter, the value the property is being assigned to.

let obj = {
    data: 1, // data property
    get accessor () { // accessor get
        console.log('get called');
        return 2;
    },
    set accessor (value) { // accessor set
        console.log('set called: ' + value);
    },
}

obj.data = 0;
obj.accessor; // get called (evaluates to 2)
obj.accessor = 3; // set called: 3

You don’t have to include both a getter and a setter for an accessor property. You can include only one or the other. Having just a getter makes the property read-only while having just a setter (far less common) means you can set a property but not have a way to get it. Note that if in strict mode, trying to use a setter when one is not defined will result in an error. Getting an accessor property without a getter will simply return undefined.

let time = {
    get current () {
        return new Date().toLocaleTimeString();
    }
};
console.log(time.current); // 10:30:00 AM
time.current = 'yesterday'; // ignored or TypeError if strict mode
// (time travel not yet possible)

The get and set syntax only works with object literals and class definitions; they do not work with existing objects. If you want to add an accessor property to an existing object you can use Object.defineProperty(). In the property descriptor object given to Object.defineProperty(), you use methods named get and set which will be used as the getter and setter methods respectively.

let rect = { width: 10, height: 5 };
Object.defineProperty(rect, 'area', {
    get () {
        return this.width * this.height;
    },
    set (value) {
        throw new TypeError('Property area cannot be set');
    }
});
console.log(rect.area); // 50
rect.area = 100; // TypeError: Property area cannot be set

Accessor properties are a great way to give added functionality to normal property usage. This can be used for computed properties (seen above with rect), input validation, triggering renders on state changes, or any number of other things. One thing to keep in mind, though, is that when working with accessor properties, your options are limited. A setter, for example, only ever receives one argument, the value being assigned. If you think you might want more, you might want to consider using a normal method instead.

More info: