Faster Programming Part 3 Getters Setters Variable Function Names

Faster programming (with ES6): Magic Getters, Setters and Variable Function Names (Part 3/4)

Avatar von Alex Aulbach

The aim of this series is to show you how to program faster by writing less code. In part one you get an overview what I mean by writing less code, part 2 shows how destructuring works, how you can use the arrow function and default Params to reduce code. Here in part 3 you’ll learn more about magic getters/setters and the Variable Function Names.

Magic Getter/Setter (ES6)

ES6 knows – like some other languages – magic getters and setters. That’s how they work:

class Person {
        constructor() {
                this.data = {};
        }
 
        get first() {
                return this.data.first || 'UNKNOWN';
        };
 
        set first(name) {
                this.data.first = name;
        };
}
 
var p = new Person();
 
console.log(p.first);  // UNKNOWN
p.first = 'Hugo';
console.log(p.first);  // Hugo

You can remove and add (and so change) the getters and setters at runtime! This enables some kind of clever self-modifying code. You can use it for lazy-loading or other types of clever caches without cache-miss errors. In this example we calculate something only once and only as getter:

class Person {
        constructor(data) {
                this.data = data;
        }
 
        get first() {
                console.log('The Getter is called');
                // calculate or load complex stuff here:
                var calculatedValue = this.data.first || 'UNKNOWN';
                Object.defineProperty(this, 'first', { value: calculatedValue });
                return calculatedValue;
        };
}
 
var p = new Person( {first: ''} );
> console.log(p.first); // initial call
The Getter is called
UNKNOWN
> console.log(p.first); // second call
UNKNOWN

What does this?

I call it a one-time lazy loading cache. When calling the getter the first time, it calculates or loads some complex stuff (line 9) – something which takes some time to compute, not just this simple code. Then we replace the getter by the calculated value using defineProperty(). That replaces the getter with the value of what we have calculated. And to end this function up we return that value.

For the second call, the getter has been overwritten with the value, so ES6 takes the value and returns it. Which creates a very simple one-time-cache, useful for such cases, where you need the cached value either never or many times.

Some of my colleagues don’t like it, and they are right. Such constructs are a typical case which needs to be discussed in a team. Because it has pros and cons. Pro: it‘s not possible to write a one-time lazy loading cache much smaller, but still readable. Con: it has some unexpected behavior. Like you cannot set the value from outside, even if you define it publicly, because the prototype is by default not writeable. See more about object prototypes.

Variable Function Names

JavaScript enables more strange things. Names of properties can be expressions. We can combine that with magic getter/setter:

// you need to define the expression, before you define the function
firstname = 'surname';
 
class Person {
        constructor() {
                this.data = {};
        }
        // this is the value of the variable firstname, which is surname
        get [firstname]() {
                console.log('The Getter is called');
                return this.data.first || 'UNKNOWN';
        };
        set [firstname](name) {
                console.log('The Setter is called');
                this.data.first = name;
        };
}
 
var p = new Person();
> console.log(p.firstname);
undefined
> console.log(p.surname);
The Getter is called
UNKNOWN
> p.surname = 'Hugo';
The Setter is called
'Hugo'
> p.first = 'Gerd';
'Gerd'
> console.log(p.surname);
The Getter is called
Hugo
> console.log(p.first);
Gerd

Define propper public/private variables because otherwise it may become quite confusing.
A better use-case is in TypeScript, that you can walk through the interface definition. So this is used as generic (data) mapper or generator. Like mapping the name and shipping address of Person to some Basket. You need just a list of left-to right-side-values. Something like that may be used in an ORM (and so normally hidden from you as a programmer). But for simpler tasks, this might be the right grade of complexity.

I discussed that in conjunction with the GDPR. The methods I show here can be used to guarantee that no data ever gets out of control. The more basic question here is if JavaScript is the right language for something like that.

This examplealso shows that self-modifying code is not always bad. It would be foolish not to use such techniques today, if useful (see part 1 about when it is useful and when not).

But I hope you have learned also, that you should never write such code alone. Try to explain the problem you want to solve to your team. Then try to explain your solution and discuss it with the goal to find a better solution. This is the most effective way to keep the code at an optimum between maintainability and complexity. Which gives me the cue for part 4 that will be about other unconventional techniques besides pure coding.

Avatar von Alex Aulbach

Kommentare

Eine Antwort zu „Faster programming (with ES6): Magic Getters, Setters and Variable Function Names (Part 3/4)“

  1. Lesetipp: Faster programming (with ES6): Magic Getters, Setters and Variable Function Names (Part 3/4)… https://t.co/wfQvInG2Qd

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert


Für das Handling unseres Newsletters nutzen wir den Dienst HubSpot. Mehr Informationen, insbesondere auch zu Deinem Widerrufsrecht, kannst Du jederzeit unserer Datenschutzerklärung entnehmen.