Immer wieder bin ich über zwei Javascript-Propertys gestolpert, die ich nicht wirklich zu unterscheiden wusste: Sowohl mit prototype
wie auch mit __proto__
kann man auf den Prototype eines JS-Objekts zugreifen und diesen beispielsweise erweitern.
Prototypen in Javascript
Prototypen dienen in Javascript dazu, eine Art der Vererbung zu realisieren, die es aufgrund der nicht vorhandenen Klassen nicht direkt gibt. Objekte in Javascript haben einen Prototypen, diese wiederum können ebenfalls einen haben. Erzeugt man etwa ein leeres Objekt, hat dieses von Haus aus einige Eigenschaften:
var a = {}; console.log(a.toString()); // "[object Object]"
Da der Interpreter die Eigenschaft toString
nicht in a
finden kann, prüft er, ob er sie in dessen Prototypen findet (und ggf. in dessen Prototypen usw.). Der Prototyp von a
ist (wenn nicht anders angegeben) ganz automatisch Object
, welches die Methode toString
bereitstellt.
Die Eigenschaft __proto__
Zwar ist dies kein ECMA-Standard, aber zumindest Chrome und Firefox vergeben jedem Objekt eine Eigenschaft __proto__
, über welche man auf den Prototypen einer Objektinstanz zugreifen kann:
var a = {}; console.log(a.__proto__.constructor.name); // "Object"
Und prototype
?
ECMA-Standard und viel verbreiteter ist aber die Eigenschaft prototype
. Anders als __proto__
wird sie aber nicht für Objekte mitgeliefert, sondern für Funktionen:
// Kein prototype in leeren Objekt: console.log(typeof ({}).prototype); // "undefined" // Dafür in einer Funktion: console.log(typeof (function(){}).prototype); // "object"
Nutzt man eine Funktion als Konstruktor, so ist der Prototyp des zurückgelieferten Objektes automatisch eine Referenz auf die Prototype-Eigenschaft der Funktion:
// Ein einfacher Konstruktor function Person(name) { this.name = name; } // prototype der Funktion erweitern... Person.prototype.greet = function() { console.log("Hello, my name is " + this.name); }; var peter = new Person("Peter"); // Prototyp ist prototype des Konstruktors: peter.greet(); // "Hello, my name is Peter"
Kurz weitergeführt, zeigt das Beispiel noch mal den Unterschied zwischen __proto__ und prototype:
var paul = new Person("Paul"); paul.greet(); // "Hello, my name is Paul" // paul ist Objekt, keine Funktion, hat // daher keine Eigenschaft prototype: paul.prototype.greet = function() { console.log("Guten Tag, mein Name ist " + this.name); }; // Uncaught TypeError: // Cannot set property 'greet' of undefined // Dafür aber die Eigenschaft __proto__ paul.__proto__.greet = function() { console.log("Guten Tag, mein Name ist " + this.name); }; paul.greet(); // "Guten Tag, mein Name ist Paul"
Gut zu wissen.
Hast du das aus dem Buch „Javascript Patterns“?
Nein, genau diese Erklärung hat mir da gefehlt, weshalb ich das hier selber mal durchgetestet habe.
Wieso fragst?
Och nur so 🙂
Hier gibts einen schönen Überblick. Da wirds sofort klar:
http://img443.imageshack.us/img443/993/jsobjects.png
Na ja, von „sofort klar“ würde ich bei der Komplexität zwar nicht sprechen, aber trotzdem danke.
Vielleicht noch zur Ergänzung / Verdeutlichung:
paul.__proto__
ist eine abkürzende Schreibweise für
paul.constructor.prototype
Guter Hinweis, auch wenn „abkürzende Schreibweise“ etwas unglücklich formuliert ist: Initial zeigen beide auf das selbe Objekt. Das kann man/sich aber jederzeit ändern.
Sorry – wenn ich dumm frage, aber schonmal Object.definePropertie oder Object.defineProperties benutzt ?
Diese zwei Methoden sind der Grund warum ECMA kein __proto__ im Standart benötigt – lol
und desweiteren erlaubt uns Javascript einfach neue Props an Objekte dran zu hängen. geht alles von alleine wie von Zauberhand 🙂
viel Spass noch beim kompliziert sein 🙂
Ich weiß jetzt nicht ob das ein Witz sein soll oder ich nicht verstehe was du meinst. Dieser Artikel behandelt Javascripts Prototyping, ich sehe nicht was
Object.defineProperty
damit zu tun haben sollte. Dass man Objekte ändern kann sollte klar sein, wird im Artikel mehr als einmal gemacht.