Wie Sie sich erinnern, haben wir in der Erklärung für Prototypen das dreischichtige Glasmodell verwendet, und dennoch schienen wir nur die ersten zwei Ebenen zu nutzen. Wie Sie vermutlich schon erraten konnten, gibt es auch Wege noch weitere Ebenen hinzuzufügen. Bevor wir jedoch zu diesem Punkt kommen, müssen wir uns Instanzen im Detail ansehen.
Wenn eine Instanz nach einer Eigenschaft gefragt wird und sie die Eigenschaft nicht hat, wird automatisch der Prototyp der Erzeugerklasse darauf untersucht. Wenn auch der Prototyp der Erzeugerklasse die Eigenschaft nicht besitzt, ist die Geschichte noch nicht zu Ende. Der Erzeugerprototyp ist auch ein Objekt und checkt seinerseits wiederrum den Prototypen seiner Erzeugerklasse - das Objekt. Also überprüft Flash Object.prototype. Das ist ein ganz schöner Happen an Information, lassen Sie es uns im Detail ansehen ...
| Hier kommt eine weitere etwas "gedehnte" Metapher ins Spiel - stellen Sie sich vor Ihr Landsherr fragt Sie nach Geld. Sie haben keines, also was tun Sie? Nunja, wenn Sie wie die meisten Leute sind, fragen Sie die Objekte die Sie erstellt haben - Ihre Eltern. Sie wollen dem Freund also den Besitz Ihrer Eltern geben, also fragen Sie bei Ihren Eltern nach ihrem Besitz (in deren Prototypen). Was tun Eltern wenn auch Sie nicht im Besitz des gefragten Gutes sind? Nach einem kurzen Gespräch werden sie Ihnen sagen, Sie sollten bei Ihren Grosseltern nachfragen. Wenn man die menschliche Sterblichkeit einmal beiseite lässt, würden die Grosseltern wiederrum bei deren Eltern nachfragen usw. usw. Sie würden solange an der Kette Ihrer Vorfahren entlang weitergereicht, bis Sie entweder das Geld bekommen, oder beim Urpsrung des menschlichen Lebens landen. Jenachdem wen man als "Urpsrung des Bänkers" ansieht, könnte das ein Gott, der Staat, oder Object.prototype sein. Was passiert wenn Sie jede verfügbare Person gefragt haben, die ganze Nacht gebetet haben, aber das Geld immer noch nicht bekommen haben? Dann ist das nunmal so, Sie haben das Geld ganz einfach nicht bekommen, es bleibt Ihnen nichts anderes übrig als bei den nächsten Besuchen des Landsherren "nicht zuhause" zu sein. Wenn irgendjemand der Leute Ihnen das Geld geliehen hätte, hätten Sie es gerne angenommen, und wären in der Kette der Vorfahren nicht weiter gegangen. In Actionscript ist es genau dasselbe, hat es einmal eine Eigenschaft, gibt es sie direkt an den Landsherren und die Sache ist erledigt. Es ist sinnvoll sich die Prototypen-Kette so vorzustellen bis Sie sich daran gewöhnt haben. |
Woher "wissen" Objekte nun, an wen sie sich wenden sollen wenn sie eine Eigenschaft nicht haben? Es wird Ihnen bei der Erzeugung mitgegeben. Wer gibt Ihnen diese Information mit? Der Ersteller, das Elternteil. Und was sagt das Elternteil? Es sagt "Hör auf mich Kind, wenn du dich einmal ganz alleine in der kalten grausamen Welt befindest und irgendetwas brauchst das du nicht hast, wende dich zuerst an mich du bist immer willkomen alles in meinem Besitz auch zu benutzen". Bevor uns alles unklar wird, erinnern wir uns daran, dass die Klasse ihre Eigenschaften im Prototypen speichert, also heisst es wirklich dass das Objekt den Prototypen der Erzeugerklasse auf Eigenschaften prüft, die das Objekt selbst nicht besitzt.
| Hier ist der Punkt: der Prototyp ist ein Objekt (daher wird es manchmal auch als "Prototyp-Objekt" bezeichnet). Also was impliziert dies? Es impliziert dass wenn der Prototyp nach einer Eigenschaft gefragt wird, die er nicht hat, der Prototyp seiner Erzeugerklasse untersucht wird. Letzte Frage, welche Klasse erzeugt Prototypen? Vielleicht kennen wir die Antwort schon - erinnern Sie sich, Prototypen werden automatisch erstellt wenn Funktionen definiert werden, sie sind vom Typ "Object". OK, vielleicht wussten wir das noch nicht, aber Prototypen werden wirklich von der Klasse Object erzeugt. So wie alle anderen von Klassen erzeugten Instanzen (alle Objekte sind Instanzen, erinnern Sie sich?) wird Ihnen von den Elternteilen gesagt "schau in deinen Prototypen falls du mal knapp an einer Eigenschaft bist!". Demzufolge prüfen alle Prototypen (und damit auch alle Instanzen die Sie mit Hilfe eigener Klassen erstellen) mitunter Object.prototype auf eine Eigenschaft, sofern sie nicht früher gefunden wurde. Dies ist die dritte Glasebene - Object.prototype. |
Ein großer potentieller "Verwirrer": object und Object. Alle Instanzen sind Objekte, Prototypen sind Objekte, Klassen definieren Objekte... fast alle Dinge sind irgendwelche Objekte, die von irgendeiner Klasse erstellt wurden. All diese Klassen (und die daraus generierten Objekte) passen perfekt in eine Hierarchie. Die Spitze dieser Hierarchie ist sehr wichtig und benötigt einen Namen: Object. Wir haben nun viele verschiedene Arten von Objekten, manche sind direkte Instanzen der Klasse Object, andere sind zwar Objekte anderen Typs, aber auch sie erben von Object.
Nicht alles ist ein Objekt
Vielleicht denken Sie, dass Nummern und Zeichenketten (Strings) sogar noch "allgemeiner" als allgemeine Objekte sind. Wenn man sich jedoch die verfügbaren Methoden dazu ansieht scheint es anders zu sein. Ein String hat die Möglichkeit Dinge auszuführen wie "myString.substring(2,3)" oder "myString.indexOf('test')". Selbst Number-Objekte haben Eigenschaften wie Number.MAX_VALUE, neben toString und valueOf. Was nun z.B. mit Zahlen wie 5, oder 7 - sind diese nicht allgemeiner als das was "new Object()" erzeugt? Nein, da sie keine Objekte sind, sondern Zeichen. Genauso wie "Hallo" und "Welt". Oft heißt es, in Actionscript sei alles ein Objekt, aber es ist nicht die ganze Wahrheit. (Ein Funktions-aktivierungsobjekt ist ein weiteres Beispiel hierfür, es ist eine Definition und kein Objekt). Nummern sind klarerweise keine Objekte, solange sie nicht ausdrücklich mit Hilfe der Number() Funktion erzeugt wurden. trace( Number(5).toString() ); // 5 trace( 5.toString() ); // error
Strings sind auch keine Objekte solange sie nicht mit Hilfe der String() Methode erzeugt werden. Normale Strings werden automatisch in ein Objekt konvertiert wenn eine String-Methode aufgerufen wird (ausgenommen "String only" Methoden - concat, fromCharCode, slice, und substr). Es wird ein vorrübergehendes Objekt erzeugt, die Methode wird ausgeführt und das Objekt dann wieder ignoriert. Hier ein Beispiel: trace( "hello".substring(1,4) ); // ell Das macht Strings weit flexibler ohne unnötigen Overhead zum normalen Stringgebrauch hinzuzufügen, obwohl es somanche langsame Methode wie z.B. "split" erklärt. Alles muss in ein Stringobjekt konvertiert werden bevor es weiterverarbeitet wird, sogar Dinge die bereits Stringobjekte sind! |
Um zu verstehen warum alle Dinge von Object.prototype geerbt werden, ist es wichtig zu verstehen, dass "Object" selbst genauso nur eine Klasse ist. Was Objekt so speziell macht: es ist eine top-level Klasse, genauso wie "lebende Dinge" eine top-level Klasse für biologische Systeme sein kann. Wenn Sie ein Objekt erzeugen wie zB.:
x = new Object();
machen Sie nichts anderes als einen Aufruf zu dieser top-level Klasse und erzeugen den allgemeinsten Typ eines Objekts der in Actionscript möglich ist. Die Object Klasse hat zwei eingebaute Methoden in ihrem Prototypen, die toString und valueOf Methoden. Außerdem hat sie eine eingebaute Eigenschaft mit der wir uns in Kürze beschäftigen werden. Alle Objekte besitzen automatisch diese drei Teile. Wenn sie mit Hilfe der Klasse Object erstellt werden, werden die Objekte automatisch Object.prototype auf weitere Eigenschaften überprüfen. Objekte, die von irgendwelchen anderen Klassen erstellt wurden, haben auch Zugriff auf diese Eigenschaften. - Die Klasse, die sie erstellt, hat einen Prototyp (wie alle Klassen), der von Object erstellt wurde (wie alle Prototypen). Also überprüft der Prototyp das Object.prototype auf Eigenschaften, die es nicht hat. Die Instanz prüft den Klassen-prototypen, der Klassen-prototyp wiederrum prüft Object.prototype.
Alle Klassen benutzen diese Prototypen-verkettung, unabhängig davon, ob sie selbstdefinierte Klassen sind, oder schon im Flash integrierte Klassen. Ein Array ist eine Instanz der Klasse Array. Der Array hat einen Klassen-Prototypen, sein Prototyp sucht in Object.prototype nach Eigenschaften, die er selbst nicht hat. Dasselbe gilt für Color, Date und andere integrierte Funktionen die Sie benutzen, um neue Objekte zu erzeugen. Die zusätzlichen Methoden und Eigenschaften (in deren Prototyp) machen sie einzigartig, wie auch immer, diese Objekte können immer noch alles was auch top-level Objekte tun können. Indem Sie eine Instanz der Klasse Color erstellen, erhalten Sie eine Instanz die mit dem Prototypen der Klasse Color verknüpft ist. Ihre Instanz wird also auch mit Object.prototype verlinkt, da Color.prototype damit verknüpft ist. Diesselbe Situation ergibt sich wenn Sie eine Instanz Ihrer eigenen Klassen erzeugen. Die Kette für das zuvor benutzte "rover" Beispiel würde so aussehen:
Object.prototype
Dog.prototype
rover
Object.prototype hat ein kleines Zeichen das sagt "Die Sache endet hier!"
Okay, soweit so gut. Was ist genau der Mechanismus der ein Objekt wissen lässt wo es bei Bedarf nachsehen kann? Diese Verknüpfung wird durch __proto__ möglich gemacht. Es ist die dritte Eigenschaft im Object.prototype welche wir schon früher kurz angesprochen haben, und ist deshalb in allen Objekten anzutreffen. Die Aufgabe von __proto__ ist simpel, es zeigt auf das Objekt welches als nächstes geprüft werden soll, wenn das aktuelle Objekt eine gewünschte Eigenschaft nicht enthält. Mit anderen Worten ausgedrückt enthält es den Namen von "an-wen-melde-ich-mich-wenn-ich-etwas-brauche". Also zeigt instanz.__proto__ auf Klasse.prototype. Der Klassen.prototype ist auch ein Objekt, also hat er auch eine __proto__ Eigenschaft. Klasse.prototype.__proto__ zeigt zu Object.prototype. Niemand weiß wie die Entwickler auf das Wort __proto__ kamen, aber mit den vier Unterstrichen ist es leicht zu merken und von anderen Schlüsselwörtern zu unterscheiden.
| Das Geheimnis von __proto__ ist, dass es NICHT nur read-only ist. Sie können es auf beliebige Ziele abändern. So kann z.B. rover's __proto__ auf Cat.prototype zeigen anstelle von Dog.prototype, und rover wird dort nach allen Methoden und Eigenschaften suchen, die er selbst nicht hat. Es sind nicht nur Instanzen, die über diesen Weg manipuliert werden können. Sie können einem Klassen-Prototypen anweisen, an anderen Orten als Object.prototype nach Eigenschaften und Methoden zu suchen. Der Trick ist zwei Klassen zu erstellen und die __proto__ Eigenschaft des Prototyps der ersten Klasse auf den Prototyp der zweiten Klasse zeigen zu lassen (anstelle von Object.prototype). Auf diese Weise erhalten Sie eine "niedrigere" Klasse (Child Klasse, Subklasse) und eine "höhere" Klasse (Parent Klasse, SuperKlasse). Denken Sie darüber nach, der eine zeigt auf den anderen, und der zeigt immer noch auf den obersten, also sind sie "gestapelt". Wie kann man das umsetzen? Indem man (konzeptuell, nicht syntaktisch) den Prototypen einer Klasse auf den Prototypen einer anderen zeigen lässt, indem man die erste __proto__ Eigenschaft ändert. |
SubClass.prototype.__proto__ = SuperClass.prototype;
|
SubClass und SuperClass sind nur Namen die wir hier verwenden, aber sie sind oft gebräuchliche Bezeichnungen um das relative Verhältnis zweier Klassen auszudrücken. Eine Großeltern Klasse wird manchmal auch als SuperSuperClass bezeichnet. Wenn Sie nun eine Instanz der "niedrigeren" SubClass erstellen, erhalten sie folgende vier Objekte: Object.prototype SuperClass.prototype SubClass.prototype instance |
![]() |
Erinnern Sie sich, wir verknüpfen nicht die Klassen selbst, wir verlinken nur deren Prototypen. Klassen definieren Instanzen, Prototypen enthalten Eigenschaften auf die Instanzen automatisch zugreifen können.
Noch eine kurze Sache, die man über __proto__ wissen sollte, ist, dass es mehrmals benutzt werden kann um in der Prototypen-kette nach oben zu wandern. So zeigt instanz.__proto__.__proto__ auf SuperClass.prototype.
Phew, Zeit für ein Beispiel. Wir starten mit ein paar Klassen die nicht verbunden sind, aber verbunden sein müssen. Hoffentlich bringt dies ein wenig Licht in die Angelegenheit, warum Sie dies so lösen wollen, bevor wir ins Detail gehen. Hier ein paar Tiere:
![]() |
// Dog Class
Dog = function( name ){ this.name = name;}Dog.prototype.legs = 4;Dog.prototype.price = 10;
Dog.prototype.pet = true;
// Cat Class
Cat = function( name )
{
this.name = name;
}
Cat.prototype.legs = 4;
Cat.prototype.price = 5;
Cat.prototype.pet = true;
// Hamster Class
Hamster = function( name )
{
this.name = name;
}
Hamster.prototype.legs = 4;
Hamster.prototype.price = 15;
Hamster.prototype.pet = true;
Wie Sie sehen gibt es hier viele Wiederholungen. Wiederholungen machen ein Programm generell weniger flexibel und schwerer zu warten. Was würde passieren wenn Sie eine neue Alterskategorie hinzufügen wollen? Sie müssten sie an vier Stellen hinzufügen. Es wird noch schlimmer, wenn Sie eine Methode hinzufügen wollen. Es gibt nicht nur viele Code-Wiederholungen für jede Methode, wenn Sie z.B. einen Bug finden, müssen Sie jede Kopie des Codes ändern. Wenn Sie nur einen einzigen Buchstaben vertauschen, haben Sie erneut einen Bug. Dieser Bug scheint etwas anderes zu sein, Sie ändern wiederrum den Code aller Methoden, und bald gibts eine Katastrophe. Also was soll getan werden? Sehen Sie sich den Code oben an und versuchen Sie ihn neu anzuordnen, bevor Sie weiterlesen.
Die Lösung ist das Erstellen einer Parent-Kategorie (SuperKlasse) namens "Pet". All diese Tiere (und alle weiteren die später hinzukommen könnten) erben von Pet, sodass generelle Eigenschaften dort sinnvoll platziert werden können. Lassen Sie uns einzeln durch die vier Eigenschaften gehen - name, legs, price und pet - und entscheiden wohin sie gehören.
name - Alle Tiere (pets) haben Namen, also sollte er sich irgendwo in der Pet Klasse befinden. Jedes individuelle Tier hat seinen eigenen Namen, also sollte er in der Instanz enden. Der logische Platz hierfür ist der Konstruktor von Pet, gesetzt durch ein Argument während die Instanz erstellt wird. Dies setzt den Namen vom Konstruktor aus aber lässt dennoch jede Instanz über den eigenen Namen entscheiden. Wenn Sie einen Standardnamen "unbenannt" benutzen wollen, würde er in pet.prototype landen - jeder gesetzte Name einer Instanz würde ihn dann gegebenenfalls verdecken.
legs - Alle Tiere (in diesem Fall) haben Beine, und alle haben vier Beine. Also ist der logische Platz hierfür Pet.prototype mit einem Wert von vier. Bevor Sie das entscheiden sollten Sie sich jedoch sicher sein, dass sie keine nicht-vierbeinigen Tiere mit einbeziehen wollen (z.B. Schlangen, Fische, Spinnen). Wenn Sie das wollen, oder Sie das eines Tages wollen, haben Sie drei Möglichkeiten.
Sie können die Eigenschaft entweder dort beibehalten, wo sie auch wirklich gegeben ist - das macht den Code leicht verständlich und ist optimal für genügende Variationen.
Oder Sie können den Standardwert von vier Beinen in Pet.prototype speichern, und dann (im Prototyp) von nicht vierbeinigen Tieren überblenden. Dies wäre die beste Lösung wenn die meisten Tiere vier Beine haben, mit nur wenigen Ausnahmen.
Zuletzt können Sie den Pet.constructor mit einem übergebenen Argument aufrufen. Mit diesem Weg muss jedes Tier beim Erstellen wissen wieviele Beine es hat. Dies gibt die Verantwortung dem Benutzer der Klasse, dennoch wäre es die richtige Lösung für ein exotisches Tiergeschäft, wo eine konstante Variation gegeben ist.
Phew, das war keine leichte Antwort! Mit OO Programmierung werden Sie feststellen gibt es oft keine perfekte Lösung, speziell wenn Ihnen zusätzliche Bedürfnisse noch nicht vollständig klar sind. Glücklicherweise ist es jedoch sehr einfach Dinge zu ändern, wenn Sie Ihren Gedankengang ein wenig ändern.
price - Alle Tiere haben Preise, aber der Preis ist konstant innerhalb derselben Tierart und gewöhnlich gibt es keinen "Normalpreis". Der Preis sollte also so bleiben wie er ist, vielleicht zusätzlich mit einem Standardpreis in Pet.prototype wenn es Sinn macht (wie z.B. umsonst). Eine letzte Sache, wenn verschiedene Hunde und Katzen verschiedene Preise haben, dann sollten Sie im Pet.constructor gesetzt werden so wie "name".
pet - Alle Tiere sind pets, also sehr einfach.
Die letzte Sache, die es herauszufinden gilt, ist, wie wird das gelöst? Nun, das Erben von Pet.prototype ist ziemlich einfach. Alles was getan werden muss ist den Hund-, den Katze- und den Hamster-Prototypen auf Pet.prototype zeigen zu lassen (anstelle von Object.prototype), um dort Eigenschaften zu finden. Dies kann wie folgt implementiert werden:
Dog.prototype.__proto__ = Pet.prototype;
Cat.prototype.__proto__ = Pet.prototype;
Hamster.prototype.__proto__ = Pet.prototype;
Bewaffnet mit diesem Wissen und dem Wissen wie wir unsere Eigenschaften organisieren wollen, können wir nun eine voll funktionsfähige Pet Klasse mit mehreren Vererbungsebenen schreiben...
![]() |
// Pet class
Pet = function( name )
{
this.name = name;
}
Pet.prototype.legs = 4;
Pet.prototype.pet = true;
// Dog class
Dog = function( name ){ }
Dog.prototype.__proto__ = Pet.prototype;
Dog.prototype.price = 10;
// Cat class
Cat = function( name ){ }
Cat.prototype.__proto__ = Pet.prototype;
Cat.prototype.price = 5;
// Hamster class
Hamster = function( name ){ }
Hamster.prototype.__proto__ = Pet.prototype;
Hamster.prototype.price = 15;
Lassen Sie uns dies ausprobieren um sicherzustellen, dass es auch wirklich funktioniert. (in Wirklichkeit funktioniert es nicht, wissen Sie schon wo das Problem liegt?)
rover = new Dog( "Rover" );
fluffy = new Cat( "Fluffy" );
ratboy = new Hamster( "Rat-Boy" );
for(var i in rover){ trace( i + ":\t" + rover[i] ) }
/* output
pet: true
legs: 4
price: 10
*/
for(var i in fluffy){ trace( i + ":\t" + fluffy[i] ) }
/* output
pet: true
legs: 4
price: 5
*/
for(var i in ratboy){ trace( i + ":\t" + ratboy[i] ) }
/* output
pet: true
legs: 4
price: 15
*/
Die __proto__ Eigenschaft hat ihre Aufgabe erfüllt. Die Eigenschaften in Pet.prototype (legs und pet) sind in allen Instanzen verfügbar. Die Instanzen erhalten außerdem die Eigenschaften von deren Konstruktor-Prototypen (price).
Das Problem mit obigem Code ist, dass die name-Eigenschaft verlorgengegangen scheint. Selbst bei genauerem Nachsehen werden wir feststellen, dass sie nirgendwo gefunden werden kann. Als wir eine neue Instanz erstellt haben, wurde der Konstruktorcode der Klasse durchlaufen. Wie auch immer, wir haben die name-Eigenschaft in den Konstruktor der Pet Klasse gelegt um uns das immer-wieder schreiben des Codes für alle Pets (die einen Namen haben) zu ersparen. Dennoch wird dieser Konstruktor nie ausgeführt. Sie können diese Art der Vererbung benutzen und alle Konstruktoren leer lassen außer dem in der untersten Ebene. Der technische Ausdruck hierfür ist "three-legged-dog" Vererbung. Obwohl es auf diesem Wege möglich ist, sinnvolle Programme zu schreiben, sind wir einer "Komplettlösung" sehr nahe. Prinzipiell müssen wir Konstruktoren der höheren Ebenen vor den Konstruktoren der unteren Ebenen zur Ausführung bringen...
Wenn man ein Programm hat, welches sich nicht wunschgemäß verhält, ist die beste Lösung das Problem zu isolieren. Auf diese Weise kann man das Problem fast immer auf eine einzige oder wenige Zeilen Code reduzieren (wenn nicht haben Sie unter Umständen ein Problem!). Also, um unser Problem zu definieren:
Obwohl unsere Instanzen die Eigenschaften von mehreren Ebenen mit Hilfe der prototype-Kette erben, wird nur der erste (auf "niedrigstem" Level befindliche) Konstruktor ausgeführt.
...um einige wenige Zeilen Code zu isolieren:
Pet = function( name )
{
this.name = name;
}
Dog = function( name ){ }
Dog.prototype.__proto__ = Pet.prototype;
rover = new Dog( "Rover" );
// test
trace(rover.name); // undefined
Als erstes wird man dazu verleitet, einfach den Pet-Konstruktor jedesmal auszuführen, sobald ein Hund erstellt wird. - Einfach vom Dog Konstruktor aus aufrufen, richtig!? - Bevor der Applaus zu laut wird, es funktioniert so nicht. Um zu verstehen, warum, müssen wir den Gültigkeitsbereich genau unter die Lupe nehmen, vielleicht hilft es uns wieder auf die "Objekte sind Kartons/Container" Metapher zurückzukommen. So könnte es aussehen:
Dog = function( name )
{
Pet( name );
}
Dog.prototype.__proto__ = Pet.prototype;
rover = new Dog( "Rover" );
Wenn hier Pet() aufgerufen wird, wird es von innerhalb des "Aktivierungsobjekts" der Dog Klasse aufgerufen (der Codeblock unterhalb der Klasse). Wenn hier Pet() also als Methode aufgerufen wird (nicht als Klasse, da es nicht mit dem "new" Operator aufgerufen wird), zeigt der Wert von "this" auf den Aufrufer, in diesem Fall also auf das Aktivierungsobjekt. Von dem was wir bereits über Aktivierungsobjekte wissen, wird es nach dem Ausführen des Konstruktors ignoriert. Was wir also zu tun haben ist den Pet-Konstruktor aufzurufen, jedoch im Gültigkeitsbereich der Instanz. In Flash 5 gab es zwei Lösungen für dieses Problem, eine schreckliche und eine aufwendigere weniger schreckliche. Dank dem neuen Schlüsselwort "super" gibt es nun eine saubere Lösung für Flash MX. Während "this" auf den Aufrufer der Klasse zeigt, können wir mit Hilfe von "super" auf den übergeordneten Konstruktor zugreifen, ein Beispiel hierfür ist:
Pet = function( name ) { this.name = name; } |
![]() |
Dog = function( name )
{
// rufe den Konstruktor der Superklasse auf
super( name );
}
Dog.prototype.__proto__
= Pet.prototype;
Dog.prototype.__constructor__ = Pet;
rover = new Dog( "Rover" );
// test
trace(rover.name); // Rover
Wunderbar! - Es funktioniert! Der Aufruf von super( ) wurde korrekt ausgeführt und führte den Pet Konstruktorcode aus! Wie Sie sicher bemerkt haben, haben wir Dog.prototype.__constructor__ auf Pet zeigen lassen, damit unser super() Aufruf korrekt den Konstruktor der Klasse Pet ausführt, währenddessen die Prototypen zuweisung die korrekte Übernahme aller Eigenschaften regelt.