born83.com frontend development

Get und Set Methoden in JavaScript

Der letzte Artikel war eine Einführung in das Thema Klassen in JavaScript. In diesem Artikel wird das Thema Klassen in JavaScript weiter vertieft und ein Blick auf sogenannte “Zugriffsmethoden” in JavaScript geworfen.

Das Geheimnisprinzip in der Objektorientierung

Ein wesentliches Paradigma der Objektorientierung ist das Geheimnisprinzip: Attribute einer Klasse sind nicht ohne Weiteres von Außen zugänglich und dürfen auf keinen Fall direkt von Außen manipuliert werden.

Dazu bedient man sich spezieller Abfragemethoden und Änderungsmethoden, auch umgangssprachlich Getter und Setter genannt.

Mit ECMAScript 6 haben diese nun auch in JavaScript Einzug erhalten.

Get und Set Methoden in JavaScript verwenden

In JavaScript-Klassen lassen sich get() und set() direkt als Schlüsselwörter verwenden:

class Dog {
    constructor(name) {
        this.name = name;
    }
    get name() {
        console.log("Methode get() aufgerufen");
        return this._name;
    }
    set name(neuerName) {
        console.log("Methode set() aufgerufen");
        this._name = neuerName;
    }
}

Instanziieren wir nun ein Objekt der Klasse Dog und lassen uns dieses ausgeben:

let snoopy = new Dog("Snoopy");
console.log(snoopy);
console.log(snoopy.name);

Wir sehen, dass der Konstruktor der Klasse die set()-Methode aufruft, um die Property name zu setzen und auch beim vermeintlich direkten Zugriff auf die Property snoopy.name wird die get() Methode aufgerufen. Die Property name wird also nicht mehr dirket gesetzt und ausgelesen, sondern es erfolgt ein indirekter Zugriff über die versteckte Property _name mit Hilfe der Methoden get() und set(). Dazu bedient man sich der Unterstrich Konvention. Es wird also eine Hilfs-Variable eingeführt, die mit einem Unterstrich beginnt und die den eigentlichen Wert der Variable beinhaltet. Im Gegensatz zu anderen Programmiersprachen ist diese aber nicht privat, d.h. der Zugriff von Außen und auch die Modifikation außerhalb der Klasse ist möglich:

let snoopy = new Dog("Snoopy");
snoopy._name = "Lassie";
console.log(snoopy.name);

Die Ausgabe zeigt: durch die Zeile snoopy._name = "Lassie"; wird die Property _name direkt geändert. Anders als man erwarten könnte, wird kein Zugriffsfehler ausgegeben. Die versteckte Property ist also wirklich nur eine Hilfsvariable und keine geschützte Variable. Das Problem bei dieser Änderung ist nun, dass der Aufruf der set() Methode umgangen wird, was vor allem zu Problemen führt, wenn diese weitere Anweisungen enthält. Dadurch gehen die Vorteile der get() und set() Methoden verloren.

Vorteile der get() und set() Methoden in JavaScript

Die Verwendung der Methoden get() und set() bietet einige Vorteile:

Vorteile bei der Anwendung der get() Methode:

Formatierung des Ausgabewertes:

get name() { 
    return this._vorname + " " + this._nachname; 
}

Der Aufruf der Property person.name führt nun zu einer Rückgabe des zusammengesetzten Strings aus den Properties vorname und nachname.

Einfache Erweiterbarkeit des Objekts um neue Funktionen:

class Mitarbeiter {
    constructor() {
        this._mitarbeiten = [];
    }
    get mitarbeit() {
            return this._mitarbeiten;
    }
    set mitarbeit(neueMitarbeit) {
        this._mitarbeiten.push(neueMitarbeit);
    }
    get aktuelleMitarbeit() {
      if (this.mitarbeit.length == 0) {
        return "Keine aktuelle Mitarbeit";
      }
      return this.mitarbeit[this.mitarbeit.length - 1];
    }
}

let mitarbeiter = new Mitarbeiter();
console.log(mitarbeiter.mitarbeit);
mitarbeiter.mitarbeit = "Projekt Benzinmotor";
mitarbeiter.mitarbeit = "Projekt Dieselmotor";
mitarbeiter.mitarbeit = "Projekt Elektrofahrzeuge";
console.log(mitarbeiter.mitarbeit);
console.log(mitarbeiter.aktuelleMitarbeit);

Die Funktion aktuelleMitarbeit() lässt sich nun wie eine Property aufrufen. Es ist also kein Funktionsaufruf mitarbeiter.aktuelleMitarbeit() notwendig.

Vorteile bei der Anwendung der set() Methode:

Validierung übermittelter Daten

Für die Variable name wäre beispielsweise die Überprüfung des Wertes neuerName auf den Typ String eine denkbare Anforderung:

class Dog {
    constructor(name) {
        this.name = name;
    }
    get name() {
        return this._name;
    }
    set name(neuerName) {
        if(typeof neuerName === "string") {
            this._name = neuerName;
        }
    }
}

let snoopy = new Dog("Snoopy");
console.log(snoopy);
snoopy.name = 19;
console.log(snoopy);

So ist sichergestellt, dass nur valide Werte vom Typ String als Name akzeptiert werden.

Weiteren Code ausführen

Dies ist besonders praktisch, wenn die Änderung einer Property weitere Anpassungen erforderlich macht. Beispielsweise könnte die Änderung der Property mitarbeit eines Mitarbeiters aus dem obigen Beispiel weitere Anpassungen nach sich ziehen. Eine Zuordnung zu einer bestimmten Experten-Gruppe abhängig von der Mitarbeit an einem bestimmten Projekt oder aber die Vergabe eines besonderen Status abhängig von der Anzahl der Mitarbeiten wäre hier denkbar. Diese könnten zentral in der set() Methode implementiert werden, damit die Überprüfung und Einordnung bei jeder Änderung der Property mitarbeit sichergestellt ist.

Zugriffsschutz

Sollen beispielsweise nur bestimmte User Properties ändern können, ließe sich diese Zugriffsbeschränkung zentral in der set() Methode implementieren und müsste nicht an jeder Stelle einzeln implementiert werden, an der eine Änderung der Property erfolgt.

Versteckte Properties JavaScript

Wie bereits oben erwähnt sind die Properties, dessen Zugriff mit Abfragemethoden und Änderungsmethoden erfolgt nicht wirklich versteckt, geschweige denn geschützt. Der Zugriff und die Manipulation von Außen ist möglich. Hier stellt die Verwendung von Symbolen und Modulen eine Möglichkeit dar, mit dessen Hilfe Properties besser versteckt und geschützt werden.


Mehr zu get() und set() Methoden unter ECMAScript 6

Mehr Informationen zu den Methoden get() und set() gibt es hier:

https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Functions/get

https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Functions/set

https://www.ecma-international.org/ecma-262/6.0/#sec-get-o-p

https://www.ecma-international.org/ecma-262/6.0/#sec-set-o-p-v-throw