In JavaScript können Funktionen Eigenschaften haben. Jede Funktion besitzt eine spezielle Eigenschaft namens prototype
.
function doSomething() {}
console.log(doSomething.prototype);
// Funktionen in JavaScript haben immer eine Standard-Prototype-Eigenschaft
// Ausnahme: Pfeilfunktionen haben keine Standard-Prototype-Eigenschaft
const doSomethingFromArrowFunction = () => {};
console.log(doSomethingFromArrowFunction.prototype);
doSomething()
hat eine Standard-prototype
-Eigenschaft. Nach Ausführung des obigen Codes zeigt die Konsole ein Objekt ähnlich dem folgenden an:
{ constructor: ƒ doSomething(), [[Prototype]]: { constructor: ƒ Object(), hasOwnProperty: ƒ hasOwnProperty(), isPrototypeOf: ƒ isPrototypeOf(), propertyIsEnumerable: ƒ propertyIsEnumerable(), toLocaleString: ƒ toLocaleString(), toString: ƒ toString(), valueOf: ƒ valueOf() } }
Hinweis: Die Chrome-Konsole verwendet [[Prototype]]
, um den Prototyp des Objekts gemäß der Spezifikation darzustellen; Firefox verwendet .prototype
. Der Einheitlichkeit halber verwenden wir [[Prototype]]
.
Wir können dem Prototyp von doSomething()
Eigenschaften hinzufügen:
function doSomething() {}
doSomething.prototype.foo = "bar";
console.log(doSomething.prototype);
Ergebnis:
{ foo: "bar", constructor: ƒ doSomething(), [[Prototype]]: { constructor: ƒ Object(), hasOwnProperty: ƒ hasOwnProperty(), isPrototypeOf: ƒ isPrototypeOf(), propertyIsEnumerable: ƒ propertyIsEnumerable(), toLocaleString: ƒ toLocaleString(), toString: ƒ toString(), valueOf: ƒ valueOf() } }
Mit dem Operator new
kann eine Instanz von doSomething()
basierend auf diesem Prototyp erstellt werden. Der Aufruf der Funktion mit dem Operator new
gibt ein Objekt zurück, das eine Instanz der Funktion ist. Diesem Objekt können dann Eigenschaften hinzugefügt werden.
function doSomething() {}
doSomething.prototype.foo = "bar"; // Eigenschaft zum Prototyp hinzufügen
const doSomeInstancing = new doSomething();
doSomeInstancing.prop = "some value"; // Eigenschaft zum Objekt hinzufügen
console.log(doSomeInstancing);
Ergebnis:
{ prop: "some value", [[Prototype]]: { foo: "bar", constructor: ƒ doSomething(), [[Prototype]]: { constructor: ƒ Object(), hasOwnProperty: ƒ hasOwnProperty(), isPrototypeOf: ƒ isPrototypeOf(), propertyIsEnumerable: ƒ propertyIsEnumerable(), toLocaleString: ƒ toLocaleString(), toString: ƒ toString(), valueOf: ƒ valueOf() } } }
[[Prototype]]
von doSomeInstancing
ist doSomething.prototype
. Beim Zugriff auf eine Eigenschaft von doSomeInstancing
prüft die Runtime zunächst, ob doSomeInstancing
diese Eigenschaft besitzt.
Falls nicht, sucht die Runtime die Eigenschaft in doSomeInstancing.[[Prototype]]
(also doSomething.prototype
). Wenn doSomeInstancing.[[Prototype]]
die gesuchte Eigenschaft hat, wird diese Eigenschaft verwendet.
Andernfalls wird doSomeInstancing.[[Prototype]].[[Prototype]]
geprüft. Standardmäßig ist [[Prototype]]
der prototype
-Eigenschaft jeder Funktion Object.prototype
. Daher wird doSomeInstancing.[[Prototype]].[[Prototype]]
(also doSomething.prototype.[[Prototype]]
oder Object.prototype
) durchsucht. Dieser Vorgang wird als Prototypenkette bezeichnet.
Wenn die Eigenschaft nicht in doSomeInstancing.[[Prototype]].[[Prototype]]
gefunden wird, wird doSomeInstancing.[[Prototype]].[[Prototype]].[[Prototype]]
durchsucht. Allerdings existiert doSomeInstancing.[[Prototype]].[[Prototype]].[[Prototype]]
nicht, da Object.prototype.[[Prototype]]
null
ist. Nachdem die gesamte Prototypenkette durchsucht wurde, stellt die Runtime fest, dass die Eigenschaft nicht existiert und der Wert der Eigenschaft undefined
ist.
function doSomething() {}
doSomething.prototype.foo = "bar";
const doSomeInstancing = new doSomething();
doSomeInstancing.prop = "some value";
console.log("doSomeInstancing.prop: ", doSomeInstancing.prop);
console.log("doSomeInstancing.foo: ", doSomeInstancing.foo);
console.log("doSomething.prop: ", doSomething.prop);
console.log("doSomething.foo: ", doSomething.foo);
console.log("doSomething.prototype.prop:", doSomething.prototype.prop);
console.log("doSomething.prototype.foo: ", doSomething.prototype.foo);
Ergebnis:
doSomeInstancing.prop: some value
doSomeInstancing.foo: bar
doSomething.prop: undefined
doSomething.foo: undefined
doSomething.prototype.prop: undefined
doSomething.prototype.foo: bar