Prototype – Das Werkzeug für Superhelden

Beim Thema Prototype stoße ich immer wieder auf mangelnde Akzeptanz anderer App Entwickler. Viele verurteilen es, ohne die Hintergründe dieser Technik zu kennen. In diesem Artikel möchte ich erklären, wann und warum man auf jeden Fall Prototype nutzen sollte. Dabei gehe ich auf die Programmierweise, aber auch auf die Hintergrundtechnik ein. So lernt ihr nicht nur, den Code eurer App angenehmer zu gestalten, sondern auch performancetechnisch zu optimieren.

Warum Prototype? Wie funktionieren Klassen überhaupt?

Um die Vorteile von Prototype zu verstehen, ist es wichtig zu verstehen wie Klassen funktionieren und dies nicht nur in JavaScript.
Der Aufbau einer Klasse ist meist simpel. Eine Klasse hat in der Regel Funktionen und Attribute. Attribute sind hier gleichzusetzen mit Variablen. Jede Instanz hat ihre eigenen Attribute, während sie aber die Funktionen mit den anderen Instanzen der Klasse teilt. Das bedeutet, dass Funktionen nicht für jedes Instanzobjekt neu definiert werden müssen.
Hier ein Beispiel (nicht aus Javascript):

class Person() {
     public String vorname;
     public String nachname;
     Person(vorname, nachname) {
          this.vorname = vorname;
          this.nachname = nachname;
     }
     public String getFullName() {
          return this.nachname + ", "; + this.vorname;
     }
}

Wenn man sich diese kleine Klasse anschaut, so sieht man, dass es Personen gibt, die einen Vor- und Nachnamen haben. Und diese Personen haben eine Funktion, die uns den kompletten Namen zurückgeben. In dem Beispiel kann man sehr gut erkennen, warum es so gelöst ist. Die Attribute sind einzigartig für jede Instanz festgelegt, da sie wertvolle Informationen zu dem Objekt enthalten. Die Funktionen werden für alle Instanzen geteilt, da sie immer die gleiche Aktionen durchführen. Dadurch kann nicht nur Zeit erspart werden beim erstellen der Instanzen, sondern auch jede Menge Arbeitsspeicher, da diese Funktionen nicht erneut irgendwo hinterlegt werden müssen. Genau dieses Verhalten erreicht man in JavaScript mit Prototype.

Javascript Codevergleich der Person Klasse

Ohne Prototype

function Person(vorname, nachname) {
    this.vorname = vorname;
    this.nachname = nachname;
    this.getFullName = function() {
        return this.nachname + ", " + this.vorname;
    };
    this.getHelloText = function() {
        return "Hallo "; + this.getFullName();
    };
    this.getVorname = function() {
        return this.vorname;
    };
    this.getNachname = function() {
        return this.vorname;
    };
}

Mit Prototype

function Person(vorname, nachname) {
    this.vorname = vorname;
    this.nachname = nachname;
}
Person.prototype.getFullName = function() {
    return this.nachname + ", " + this.vorname;
};
Person.prototype.getHelloText = function() {
    return "Hallo " + this.getFullName();
};
Person.prototype.getVorname = function() {
    return this.vorname;
};
Person.prototype.getNachname = function() {
    return this.vorname;
};

Wenn man sich die beiden Codes ansieht, fällt programmiertechnisch kein großer Unterschied auf. Um genau zu sein, kann man bestehende alte Klassen ohne viel Aufwand auf Prototype umschreiben. Hier ziehen wir die Funktionen einfach aus dem Constructor raus und schieben es in Prototype rein. Sehen wir uns aber die Methode ohne Prototype ein, fällt auf, dass mit jeder neuen Instanz eine neue Funktion im Arbeitsspeicher abgelegt wird. Dies ist bei Klassen mit nur 1-10 Instanzen vielleicht noch unproblematisch. Erstellen wir aber für jeden User z.B. eine Instanz der Klasse Person, sagen wir mal mit 1000 Instanzen, so erzeugen wir im Arbeitsspeicher unnötigerweise 999*4 Funktionen.
Im Benchmark fällt dann der Unterschied auf. Während die Prototype-Variante 20kb im Arbeitsspeicher verbraucht, so verbraucht die Variante ohne Prototype 36kb Speicher. In der Regel haben Klassen noch deutlich mehr Funktionen, womit der Unterschied sehr leicht auf einen Faktor 3,5 sich zurückführen lässt.

Welche Nachteile hat Prototype

Eigentlich keine. Als Nachteil wird häufig genannt, dass kann keine privaten Variablen möglich sind. Dies ist auch so. Da wir aber 2 Situationen haben in JavaScript, nämlich möglicher Angreifer hat Quellzugriff (UI) und möglicher Angreifer muss erst den KnuddelsServer hacken (AppServer), ist dieses argument hinfällig, warum man private Variablen nutzen muss. Sicher ist es wichtig, Variablen nur in ihrem Scope zu nutzen. Hier kann man aber this nutzen. Um für sich selbst als Entwickler „private“ Variablen dort zu markieren, werden diese in der Regel mit einem Unterstrich geschrieben. Also this._kontonummer = 123456789;

Welche Vorteile hat Prototype

Neben der ernormen Speicher- und Prozessorschonung bietet Prototype auch weitere Vorteile. So kann man mit Prototype Vererbungsketten erstellen und somit auch mit Polymorphie arbeiten. Außerdem lassen sich schon bestehende Klassen erweitern. Hier kann man z.B. die Userklasse von Knuddels erweitern um eine eigene Funktion direkt an das Nutzerobject zu binden. Wichtig hierbei: Knuddels könnte später eine solche Funktion selber einbauen mit gleichem Namen, welches eure Funktion überschreibt. Daher sollte man auch hier alle Funktionsnamen mit einem Unterstrich beginnen.

User.prototype._setGamePoints = function(pts) {
    this.getPersistence().setNumber('gamepoints', pts);
}

Fazit

Wer kein Problem damit hat, ein bisschen anders zu arbeiten, sollte auf Prototype umsteigen. Bestehende Klassen lassen sich blitzschnell in Prototype umschreiben. Wir sollten alle daran denken, dass wir uns die Server teilen und mit Prototype die Server schonen können und uns allen somit mehr Ressourcen zur Verfügung stehen. Ich habe am Anfang auch mit Prototype Probleme gehabt, aber wenn man sich ordentlich einliest und ein wenig mit einer Suchmaschine herumsucht, findet man immer schnell eine Lösung für ein aufkommendes Problem. Im Zweifelsfall bleibt euch immer noch der Weg ins Entwickler-Forum!

2 Gedanken zu “Prototype – Das Werkzeug für Superhelden

  1. Hallo,

    wer voraussehen kann, dass ein Objekt mehrfach vorhanden ist sollte generell immer Prototype-Methoden verwenden (sonst Instanzmethoden). Durch die Verwendung werden allerdings alle privaten Eigenschaften öffentlich. Die Verwendung des IIFE-Pattern und Closures schafft hier abhilfe sodass man private Eigenschaften mit nichtprivilegierte Methoden nutzen kann.

    Nachfolgend ein Beispiel: https://gist.github.com/anonymous/68695ffc6d92e0af52751ed47bd2c941

    Gruß Daniel.

    Like

Hinterlasse einen Kommentar