Prototypes
Wie wird nun in JavaScript Vererbung realisiert? Dazu zunächst eine gesonderte Betrachtung des sogenannten Prototyps.
Der Prototyp
Zur Einführung betrachten wir nochmal folgenden bekannten Code. Nach Konvention
haben wir eine Konstruktor-Funktion, Funktionen in JavaScript sind ebenso Objekte,
also haben sie auch Properties. Eine davon: prototype
function Customer( ) {
}
log(Customer.prototype);
var c1 = new Customer();
log(c1);
Der log-Ausgabe können wir entnehmen, dass der Prototyp quasi ein leeres Objekt eines Typs (name der Konstruktor-Funktion) ist. Nun lässt sich dieser natürlich erweitern:
Customer.prototype.nr = 0;
Customer.prototype.firstname = "";
Customer.prototype.lastname = "";
Customer.prototype.registerDate = undefined;
Customer.prototype.fullname = function() {
return this.firstname + " " + this.lastname
};
log(c1);
Diese Eigenschaften und Methoden kann ich natürlich auch über ein Objekt-Literal zuweisen:
// und zum Vergleich
function Product( nr, name ) {
this.nr = nr;
this.name = name;
}
console.log(Product.prototype);
var p1 = new Product(1, "Berliner Pils");
console.log(p1);
Product.prototype = {
nr: 0,
name: "",
price: 0.0,
unit: "€",
toString: function () {
return this.name + " (" + this.price + this.unit + ")"
}
};
console.log(p1);
Selbstverständlich kann ich einem einzelnen Objekt (nicht Prototyp) weitere eigene dynamische Eigenschaften zuweisen; Erweiterungen/Änderungen des Prototyps wirken sich jedoch auf alle(!) Objekte aus, die mit diesem Prototyp erstellt wurden.
Das Ersetzen des Prototypen durch einen neuen hat übrigens keine Auswirkungen auf die schon erzeugten Objekte; diese halten eine Referenz auf den bei ihrer Konstruktion gültigen Prototypen.
Zur Beantwortung der auf(ge)kommen(d)en Fragen:
- Warum erbt c1 die Prototype-Eigenschaften (leer angelegt), aber p1 (mit Konstruktor-Funktion und zwei gesetzten Eigenschaften) nicht (Merke: die Prototypen wurden jeweils hinterher angelegt)?
- Warum wirkt sich die Prototyp-Änderung auf alle Objekte aus, es sei denn die geänderte Eigenschaft war auf den Objekten schon explizit gesetzt?
Bitte versuchen Sie sich selbst an der Lösung. Tipp: interne Objekt-Property hasOwnProperty
Methoden und Funktionen
An dieser Stelle sei nochmal auf eine Besonderheit der Spezifikation im
Zusammenhang mit Funktionen hingewiesen. Nochmal die Definition: eine Methode
ist eine Funktion die ein Wert einer Eigenschaft ist. Ein wesentlicher
Unterschied zw. Funktion und Methode ist (s.o.) die this
-Referenz.
In der Funktion zeigt this
auf das globale Objekt (z.B. window
im Browser),
in der Methode auf das Objekt selbst (wie in Java ...). Demzufolge geht
folgender Code schief:
Customer.prototype.email = "";
Customer.prototype.isValid = function () {
// innere Funktion! Keine Methode!
function checkEmail() {
return this.email.match(/^\w+@\w+(\.\w{2,4})?$/);
}
if(
this.firstname && this.firstname.length > 0
&& this.lastname && this.lastname.length > 0
&& checkMyEmail()
)
return true;
else
return false;
};