Für die Erklärung der
__proto__-Eigenschaft muss ich ein kleines Stück weiter in OOP eindringen.
Wie oben bereits steht, ist
__proto__ eine Eigenschaft - nämlich genau wie
prototype eine Eigenschaft jeder Instanz im Film.
Im Gegensatz zu
prototype, welches ein Container für die Eigenschaften und Methoden einer Klasse darstellt, ist
__proto__ lediglich eine Referenz auf genau jenes zu checkende
prototype-Objekt einer Instanz.
Eine Instanz muss nämlich nicht dem Regelfall folgen und jeweils die Methode aus dem
prototype-Objekt der Mutterklasse ausführen, sondern kann genausogut das
prototype-Objekt einer "Kuckucks"klasse verwenden, das hängt ganz allein von der Gestaltung der Eigenschaft
__proto__ ab.
Ein Beispiel hierfür aus dem in diesem Falle allzuoft gewählten Vergleich einer Familie:
Eine jede Instanz ist Tochter einer Klasse, von der sie geboren wurde.
Diese Instanz bekommt auf ihren Lebensweg ein paar Hinweise von der Mutterklasse mit, diese Hinweis findet sie im
prototype-Objekt der Mutterklasse, auf die sie jederzeit zugreifen kann.
Aber woher weiß die Instanz eigentlich, wer ihre Mutter ist und auf wessen
prototype-Objekt sie zugreifen muss, wenn sie nicht weiter weiß?
Ganz richtig, hierfür bekommt die Instanz die Eigenschaft
__proto__ mit auf den Weg.
Dort schlägt sie nach, wenn sie nicht weiter weiß und wird im Standardfall auf das
prototype-Objekt der Mutterklasse verwiesen.
Ergo lautet also die vom System automatisch gesetzte Anweisung:
PHP:
Klasse.prototype.__proto__ = Klasse.prototype;
Sagt nämlich nichts anderes als "Schau bei deiner Mutter nach".
Die Eigenschaft
__proto__ ist aber nicht schreibgeschützt und kann jederzeit durch Scripting-Hand modifiziert und überschrieben werden.
Was nun, wenn sie jemand auf das
prototype-Objekt einer anderen Klasse setzt?
Schaue man nach...
PHP:
function Ekel() {}
Ekel.prototype.knutsch = function() {
trace("Igitt! Ohne mich!");
}
// die Familie der Ekel knutscht nicht gerne :-)
function Casanova() {}
Casanova.prototype.knutsch = function() {
trace("Schmatz!");
}
// die Familie der Casanovas hingegen knutscht sehr gerne
schnuckel = new Casanova(); // ein neuer Sohn der Casanovas wird geboren
schnuckel.__proto__ = Ekel.prototype; // der neugeborene Casanova-Sohn soll nicht die Gewohnheiten der Familie Casanova übernehmen sondern die der Familie Ekel
schnuckel.knutsch(); // und zack - hier der Test
Und siehe da - der Kleine lehnt trotz Casanova-Mutter dankend ab und schließt sich der Meinung von Familie Ekel an, da in seiner
__proto__-Eigenschaft nicht das
prototype-Objekt der Casanova-Klasse, sondern jenes der Ekel-Klasse referenziert wird.
Im folgenden noch eine winzige Zusammenfassung des "scoping chains" einer Instanz - also derjenigen Reihenfolge, die eine Instanz betrachtet, um eine gegebene Methode auszuführen oder eine gegebene Eigenschaft auszulesen:
- die Instanz sucht eine nur ihr selbst zugeordnete Methode
instanz.methode (ist logisch oder?)
- existiert eine solche nicht, schaut sie in ihrer
__proto__-Eigenschaft nach, welche sie auf ein entsprechendes anderes Objekt verweist, welches die Methode beinhalten könnte
Ich hoffe das Beispiel war irgendwie verständlich und nicht zu dämlich.
Bei Fragen - immerzu und her damit.
Gruß,
Adam