What is the argument for using ES6 getters and setters over getProperty/setProperty convention?

class Foo {
    getName = () => this.name;

    setName = (name) => this.name = name;
}

and

class Foo {
    get name () {
        return this.name;
    }

    set name (name) {
        this.name = name;
    }
}

I can think of several examples where ES6 getters are at a disadvantage, e.g.

You cannot write a getter that will return a value based on a parameter value:

/**
 * Returns an instance of Card associated with an element.
 *
 * @param {HTMLElement} element
 * @return {Card|undefined}
 */
getCard = (element) => {
    return _.find(this.index, {
        element: element
    });
};

That's okay, however, if you use this and ES6, you are introducing code style inconsistency.

You cannot distinguish between a direct property access and method access.

class Foo {
    get name () {
        return this.name;
    }

    get expensive () {
        // An operation that takes a lot of computational power.
    }

    get randomValue () {
        // Returns random value.
    }
}

let foo = Foo();

foo.name;
foo.expensive;
foo.randomValue;

The disadvantage is that it is not intuitive that a property that you are accessing might require heavy computational power (and therefore should be memoized) or that it changes every time you access it.

Finally, getters/setters do not work with arrow functions. Invalid example:

class Foo {
    get name = () => {
        return this.name;
    }

    set name = (name) => {
        this.name = name;
    }
}

Which exposes them to the context issues.

What is the advantage of using ES6 getters and setters over the conventional get{PropertyName} and set{PropertyName} abstraction?

Answers:

Answer

You cannot distinguish between a direct property access and method access.

This is the main argument in their favour.

One of the weirdest great pains of writing classic Java-style OO code is that any object with an exposed property on it has to have getters and setters written, and a huge amount of boilerplate comes rolling out of this, especially for large data-structure type objects (e.g. DTOs).

The reasoning for all of these is that you can't just make properties public, because otherwise you can't ever add logic to them without breaking the API (e.g. logic to only allow settings certain values, or to refactor and store a property in a slightly different way while still exposing the same external API, or similar). See https://softwareengineering.stackexchange.com/questions/176876/why-shouldnt-i-be-using-public-variables-in-my-java-class for some typical arguments around this.

I think you could comfortably say that this has been taken to its logical extreme in recent years, but that doesn't mean it's wrong; by exposing a public field for direct access you are indeed exposing the internal implementation of how you're storing that data, and that means you can't change it as easily or safely any more.

ES6 getters/setters fix this. The fact that something is readable as a direct property on an object no longer tells you anything about the implementation of that property. It could have been a field originally, but recently turned into a ES6 property accessor instead, without the API changing. The implementation of the property is hidden from the rest of your codebase, and is therefore easier to change.

The disadvantage is that it is not intuitive that a property that you are accessing might require heavy computational power (and therefore should be memoized) or that it changes every time you access it.

You're right, this is a risk. That's also a gotcha with any getX() though; there's a strong convention suggesting that nice simple methods like 'getName()' shouldn't ever be doing expensive things behind the scenes, even if they are methods, and if you break that you'll almost certainly end up catching people out (including yourself, 6 months from now)

Moving to properties doesn't change this, but you're right that ES6 means you're no longer guaranteed to be safe for simple property accesses. The answer is really just that you have to make sure you (and everybody else) sticks with convention and Principle of Least Astonishment: as with existing simple looking getters and setters, ES6 property accessors should do simple cheap things, and shouldn't have strange side effects elsewhere.

Answer

There aren't any specific things you can't do with getMethod() and setMethod(), but it allows for different code styles. For instance you could, with a get foo and set foo, write:

obj.foo++;

which would call the getter then the setter. You could, of course, have the set function then validate that the value is within a specific range, for instance. The traditional code would look like:

obj.setFoo(obj.getFoo() + 1);

You cannot distinguish between a direct property access and method access.

That's kinda the point. I'd argue that if something is really expensive, you just shouldn't use getters for it.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.