Features von übermorgen: ES7 Decorators

Tales from the Web side  –  0 Kommentare

Während ES6 in den Startlöchern steht, gehen bereits fleißig weitere Beiträge für ES7 ein. Einer davon ist der vor Kurzem veröffentlichte Vorschlag der sogenannten Decorators von Yehuda Katz.

Decorators sind in etwa vergleichbar mit Annotationen, wie man sie beispielsweise aus Sprachen wie Java oder aus dem mittlerweile wieder verworfenen AtScript kennt. Wie sie verwendet werden können, zeigt der folgende Beitrag. Vorweg muss man allerdings sagen, dass Decorators momentan nur mit dem Babel-Compiler funktionieren, für den es aber dankenswerterweise online die Möglichkeit gibt, ohne Installations- und Konfigurationsaufwand verschiedene ES6- und ES7-Features schnell und unkompliziert auszutesten.

Das Prinzip der Decorators

Das Prinzip der Decorators lässt sich relativ einfach zusammenfassen: Ähnlich wie bei der Annotationen-Syntax zeichnet man mit Decorators bestimmte Methoden einer Klasse oder die Klasse an sich aus. Wird die Klasse dann initialisiert, wird vorher der entsprechend gesetzte Decorator aufgerufen. Dabei handelt es sich letztlich um eine einfache Funktion mit drei Parametern: dem Objekt, auf dem die Methode definiert ist (target), dem Namen der Methode (name) und dem Property Descriptor (descriptor), sprich dem Objekt, welches verschiedene Eigenschaftsattribute enthält.

Folgendes Listing zeigt dazu ein einfaches Beispiel. Ganz oben sieht man zunächst die Definition des Decorators, wie gesagt eine simple Funktion mit drei Parametern. Die Methode calculateSum() der Calculator-Klasse wird anschließend über @decoratorFunction mit dem Decorator ausgezeichnet, was dafür sorgt, dass die Funktion decoratorFunction() vor Initialisierung der Klasse Calculator selbst aufgerufen wird.

function decoratorFunction(target, name, descriptor) {
console.log(target); // im Beispiel: Calculator {}
console.log(name); // im Beispiel: calculateSum
console.log(descriptor); // im Beispiel: Object {value: function,
enumerable: false, configurable: true, writable: true}
}

class Calculator {
@decoratorFunction
calculateSum(x, y) {
return x + y;
}
}

var calcuator = new Calculator();
var result = calcuator.calculateSum(5,5);
console.log(result);

Optional kann eine Decorator-Funktion einen Property-Descriptor zurückgeben. Im folgenden Beispiel etwa sieht man eine Decorator-Funktion, die verhindert, dass eine Methode neu definiert werden kann, indem die writable-Eigenschaft des Property Descriptors auf false gesetzt wird.

function readonly(target, name, descriptor) {
descriptor.writable = false;
}

class User {
constructor(name, password) {
this.name = name;
this.password = password;
}
@readonly
toString() {
return '[Nutzername: ' + this.name + ']';
}
}

var user = new User('Max Mustermann', 'geheimesPasswort');
console.log(user.toString());
// Fehler: 'Uncaught TypeError: Cannot assign to read only property
// 'toString' of [object Object]'
User.prototype.toString = function() {
return '[Nutzername: ' + this.name + ', Passwort: ' + this.password + ']';
}

Verwendet man eine Decorator-Funktion an einer Klasse, hat man innerhalb der Funktion nur Zugriff auf das Zielobjekt, welches in diesem Fall der entsprechende Konstruktor ist:

@component
class User { }

function component(target, name, descriptor) {
console.log(target); // im Beispiel: function User() {...}
console.log(name); // undefined
console.log(descriptor); // undefined
target.isComponent = true;
}
console.log(User.isComponent); // true

Fazit

Decorators erhöhen die Wiederverwendbarkeit des Quelltexts und bieten eine einfache Möglichkeit, Klassen und Methoden mit zusätzlichen Informationen zu versehen und Einfluss auf den Property Descriptor zu nehmen. Eine GitHub-Webseite zeigt, dass auch komplexere Konzepte wie Memoization mit Decorators umgesetzt werden können. Man darf auf jeden Fall gespannt sein, wie sich das Thema weiterentwickelt und ob es seinen Platz in ES7 findet.