Unter Vererbung und der Prototype des Konstruktors findet man eine Beschreibung zur Vererbung bei JavaScript und dem Prototype des Konstruktors.
Vererbung war von Anfang bei JavaScript vorhanden. Die Beispiele auf dieser Seite setzen jedoch einige Methoden ein, die erst mit ECMAScript 5 eingeführt wurden. Auf den entsprechenden Referenzseiten für die Methoden kann man herausfinden, ob diese sich für ältere Versionen emulieren lassen.
Beispiel
B soll von A erben:
function A(a){
this.varA = a;
}
A.prototype = {
varA : null,
doSomething : function(){
// ...
}
}
function B(a, b){
A.call(this, a);
this.varB = b;
}
B.prototype = Object.create(A.prototype, {
varB : {
value: null,
enumerable: true,
configurable: true,
writable: true
},
doSomething : {
value: function(){ // override
A.prototype.doSomething.apply(this, arguments); // call super
// ...
},
enumerable: true,
configurable: true,
writable: true
}
});
var b = new B();
b.doSomething();
Die wichtigen Teile sind:
- Typen sind in
.prototypedefiniert - Die Methode
Object.create()wird zum Vererben benutzt
prototype und Object.getPrototypeOf
JavaScript ist ein wenig verwirrend für Entwickler, die von Java oder
C++ kommen, da bei JavaScript alles dynamisch und laufzeitbasiert ist
und überhaupt keine Klassen existieren. Alles sind nur Instanzen
(Objekte). Sogar die "Klassen", die wir simulieren, sind nur function-Objekte.
Vielleicht haben Sie schon bemerkt, dass die Funktion A eine spezielle Eigenschaft prototype besitzt. Diese spezielle Eigenschaft arbeitet mit dem Operator new von JavaScript. Die Referenz auf das Prototype-Objekt wird für die interne Eigenschaft [[Prototype]] der neuen Instanz kopiert. Bei der Anweisung var a1 = new A() setzt JavaScript (nachdem das Objekt im Speicher erstellt und bevor die Funktion A() aufgerufen und this zugewiesen wurde) z. B. a1.[[Prototype]] = A.prototype.
Beim Zugriff auf Eigenschafen der Instanz überprüft JavaScript dann
zuerst, ob diese Eigenschaft direkt existiert und wenn nicht wird in [[Prototype]] gesucht. Das bedeutet, dass alles, was für prototype definiert wird, tatsächlich von allen Instanzen geteilt wird. Später kann man Teile von prototype verändern und diese Änderungen werden daraufhin, wenn man so will, für alle Instanzen übernommen.
Bei der Anweisung var a1 = new A(); var a2 = new A(); aus dem Beispiel oben, verweist a1.doSomething auf Object.getPrototypeOf(a1).doSomething, was dasselbe ist wie A.prototype.doSomething, das definiert wurde, z. B. Object.getPrototypeOf(a1).doSomething == Object.getPrototypeOf(a2).doSomething == A.prototype.doSomething.
Kurz: prototype ist für Typen und Object.getPrototypeOf() dasselbe für Instanzen.
[[Prototype]] wird rekursiv durchlaufen, z. B. a1.doSomething, Object.getPrototypeOf(a1).doSomething, Object.getPrototypeOf(Object.getPrototypeOf(a1)).doSomething usw. bis etwas gefunden wurde. Falls nichts gefunden wurde, gibt Object.getPrototypeOf den Wert null zurück.
Beim Aufruf:
var o = new Foo();
macht JavaScript also folgendes:
var o = new Object();
o.[[Prototype]] = Foo.prototype;
o.Foo();
(oder ähnliches) und wird später diese Anweisung ausgeführt:
o.someProp;
Dann wird erst überprüft, ob o die Eigenschaft someProp besitzt. Wenn nicht, wird Object.getPrototypeOf(o).someProp überprüft und wenn die Eigenschaft auch dann nicht gefunden wurde, wird Object.getPrototypeOf(Object.getPrototypeOf(o)).someProp
überprüft. Dies wird solange fortgesetzt, bis die Eigenschaft entweder
gefunden oder festgestellt wurde, dass sie nicht existert.