Vererbung mit JavaScript

In einer Vorlesung wurde das Konzept der Vererbung grundlegend erläutert und in einer Übungsaufgabe illustriert, wie das in prototypbasierten Sprachen aussehen kann. Wir sollten meine alte Freundin JavaScript mit dem Interpreter von Mozilla benutzen. Subtyping und Vererbung ist für JavaScript wohl nur ansatzweise und unbehände gelöst; zahlreiche Quellen im Web führten mich zu Lösungen, die als Prototyp eines Subtyps ein Object des Supertyps setzten. Das sah in etwa so aus:

function Person(name) {
  var name = name;
  this.print = function() {
    print(name);
  }
}
Person.prototype = new Person("A");

function Student(name, id) {
  Person.prototype.constructor(name);
  var id = id;
  this.print = function() {
    Person.prototype.print();
    print(id);
  }
}
Student.prototype = new Person("B");

Die Notation mit den Prototypen ist ziemlich unhandlich — und auch nicht korrekt. Das Beispiel

var p = new Person("Kurt");
p.print();
print(p instanceof Person);
print(p instanceof Student);

print("");
var s = new Student("Klaus", 17);
s.print();
print(s instanceof Person);
print(s instanceof Student);

print("");
var t = new Student("Dieter", 18);
p.print();
t.print();
s.print();

erzeugt diesen Output:

Kurt
true
false

Klaus
17
true
true

Kurt
Dieter
18
Dieter
17

Es ist also immer nur ein Satz von Werten im Supertyp für alle Instanzen des Subtyps möglich. Interessant (lies: verstörend) ist auch, dass zwar alle Studenten, nicht aber reine Personen geändert werden, wo doch der Konstruktor des Prototyps von Person aufgerufen wird! Interessante Effekte gibt es auch, wenn man dem Konstruktor eines Subtyps von Person eine Instanz eines anderen Subtyps mitgibt — dann werden alle Instanzen des übergebenen Typs geändert! Eine Lösung mittels Forwarding erscheint mir da zweckdienlicher:

function Student(name, id) {
  var super = new Person(name);
  var id = id;

  this.print = function() {
    super.print();
    print(id);
  };
}
Student.prototype = new Person("B");

Der Output des obigen Tests ist nun

Kurt
true
false

Klaus
17
true
true

Kurt
Dieter
18
Klaus
17

Dies würde man auch erwarten. Nun muss bei einer solchen Lösung der Programmierer natürlich explizit jede Methode an die Instanz des Supertyps weiterleiten, Überschreiben von Methoden und öffentliche Attribute sind unmöglich, weil sie die Voraussetzungen für erfolgreiches Forwarding verletzen. Wirklich ideal ist das also auch nicht.

Ich frage mich, ob es überhaupt Sinn macht, Konzepte wie Vererbung und vielleicht sogar Subtyping in einer prototypbasierten Scriptingsprache haben zu wollen. Gerade in Sprachen JavaScript, wo Methoden und Variablen ohnehin nicht getypt sind, benötigt man explizites Subtyping nicht wirklich; eine implizite Hierarchie nach strukturellen Kriterien könnte hier genügen.

Comments are closed.