Objektprototypen in JavaScript

0 Aktien
0
0
0
0

Einführung

 

Prototypen sind der Mechanismus, durch den JavaScript-Objekte Eigenschaften voneinander erben. In diesem Artikel erklären wir, was ein Prototyp ist, wie Prototypenketten funktionieren und wie man einen Prototyp für ein Objekt festlegt.

Voraussetzungen

Machen Sie sich mit den Funktionen von JavaScript vertraut, lernen Sie die Grundlagen von JavaScript kennen (siehe Erste Schritte und Bausteine) und die Prinzipien des objektorientierten JavaScripts (siehe Einführung in Objekte).

Prototypenkette

Versuchen Sie, in der Browserkonsole ein Literalobjekt zu erstellen:

const myObject = {
city: "Madrid",
greet() {
console.log(`Greetings from ${this.city}`);
},
};
myObject.greet(); // Greetings from Madrid

Dies ist ein Objekt mit einer Dateneigenschaft, „city“, und einer Methode, „greet()“. Wenn Sie den Objektnamen gefolgt von einem Punkt in die Konsole eingeben, z. B. „myObject.“, zeigt die Konsole eine Liste aller verfügbaren Eigenschaften dieses Objekts an. Sie werden sehen, dass es neben „city“ und „greeting“ noch viele weitere Eigenschaften gibt!

__defineGetter__
__defineSetter__
__lookupGetter__
__lookupSetter__
__proto__
city
constructor
greet
hasOwnProperty
isPrototypeOf
propertyIsEnumerable
toLocaleString
toString
valueOf

Versuchen Sie, auf einen davon zuzugreifen:

myObject.toString(); // "[object Object]"

Es funktioniert (auch wenn nicht klar ist, was toString() genau bewirkt).

Was sind das für zusätzliche Eigenschaften und woher kommen sie?

Jedes Objekt in JavaScript besitzt eine eingebaute Eigenschaft namens Prototyp. Ein Prototyp ist selbst ein Objekt und hat daher einen eigenen Prototyp. Dadurch entsteht eine sogenannte Prototypenkette. Diese Kette endet, sobald ein Prototyp erreicht wird, dessen Prototyp den Wert `null` hat.

Hinweis: Eine Eigenschaft eines Objekts, die auf seinen Prototyp verweist, wird nicht als Prototyp bezeichnet. Die Bezeichnung ist nicht standardisiert, aber in der Praxis verwenden alle Browser `__proto__`. Der Standardweg, um auf den Prototyp eines Objekts zuzugreifen, ist die Methode `Object.getPrototypeOf()`.

 

Beim Zugriff auf eine Objekt-Eigenschaft gilt Folgendes: Wird die Eigenschaft im Objekt selbst nicht gefunden, wird der Prototyp der Eigenschaft durchsucht. Wird die Eigenschaft auch dort nicht gefunden, wird der Instanzprototyp durchsucht usw., bis die Eigenschaft gefunden wird oder das Ende der Suchkette erreicht ist. In diesem Fall wird `undefined` zurückgegeben.

Wenn wir also myObject.toString() aufrufen, gibt der Browser Folgendes aus:

  • Sucht nach toString in myObject
  • Ich kann es dort nicht finden, also sucht es im Prototyp des Objekts „myObject“ nach „toString“.
  • Er findet es dort und ruft es an.

Was ist der Prototyp für meinObjekt? Um das herauszufinden, können wir die Funktion Object.getPrototypeOf() verwenden:

Object.getPrototypeOf(myObject); // Object { }

Dies ist ein Objekt namens `Object.prototype` und der grundlegendste Prototyp, den alle Objekte standardmäßig besitzen. Der Prototyp `Object.prototype` ist `null`, befindet sich also am Ende der Prototypenkette.

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes/myobject-prototype-chain.svg

Der Prototyp eines Objekts ist nicht immer `Object.prototype`. Probieren Sie Folgendes:

const myDate = new Date();
let object = myDate;
do {
object = Object.getPrototypeOf(object);
console.log(object);
} while (object);
// Date.prototype
// Object { }
// null

Dieser Code erzeugt ein Date-Objekt, durchläuft dann die Prototypenkette und registriert die Prototypen. Er zeigt uns, dass der Prototyp von myDate ein Date.prototype-Objekt ist und dessen Prototyp Object.prototype ist.

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes/mydate-prototype-chain.svg

Wenn Sie bekannte Methoden aufrufen, wie zum Beispiel myDate2.getTime(), rufen Sie tatsächlich eine Methode auf, die in Date.prototype definiert ist.

Schattierungseigenschaften

Was passiert, wenn man eine Eigenschaft eines Objekts definiert, während im Prototyp des Objekts bereits eine Eigenschaft mit demselben Namen definiert ist? Mal sehen:

const myDate = new Date(1995, 11, 17);
console.log(myDate.getTime()); // 819129600000
myDate.getTime = function () {
console.log("something else!");
};
myDate.getTime(); // 'something else!'

Dies sollte angesichts der Beschreibung der Prototypenkette vorhersehbar sein. Wenn wir `getTime()` aufrufen, sucht der Browser zunächst in `myDate` nach einer Eigenschaft mit diesem Namen und prüft den Prototyp nur dann, wenn `myDate` diese Eigenschaft nicht definiert. Wenn wir also `getTime()` zu `myDate` hinzufügen, wird die Version in `myDate` aufgerufen.

Dies nennt man “Beschattung” des Grundstücks.

Einen Prototypen einrichten

Es gibt mehrere Möglichkeiten, den Prototyp eines Objekts in JavaScript festzulegen, und hier werden wir zwei davon beschreiben: Object.create() und den Konstruktor.

Mit Object.create

Die Methode Object.create() erzeugt ein neues Objekt und ermöglicht es Ihnen, ein Objekt anzugeben, das als Prototyp des neuen Objekts verwendet werden soll.

Hier ist ein Beispiel:

const personPrototype = {
greet() {
console.log("hello!");
},
};
const carl = Object.create(personPrototype);
carl.greet(); // hello!

Hier erstellen wir ein `personPrototype`-Objekt mit einer `greet()`-Methode. Anschließend verwenden wir `Object.create()`, um ein neues Objekt mit `personPrototype` als Prototyp zu erzeugen. Nun können wir `greet()` auf dem neuen Objekt aufrufen, und der Prototyp stellt die Implementierung bereit.

Verwendung des Konstruktors

In JavaScript besitzen alle Funktionen eine Eigenschaft namens Prototyp. Wenn Sie eine Funktion als Konstruktor aufrufen, wird diese Eigenschaft auf den Prototyp des neu erstellten Objekts gesetzt (konventionsgemäß in einer Eigenschaft namens __proto__).

Wenn wir also den Prototyp eines Konstruktors festlegen, können wir sicherstellen, dass alle mit diesem Konstruktor erstellten Objekte diesen Prototyp erhalten:

const personPrototype = {
greet() {
console.log(`hello, my name is ${this.name}!`);
},
};
function Person(name) {
this.name = name;
}
Object.assign(Person.prototype, personPrototype);
// or
// Person.prototype.greet = personPrototype.greet;

Hier erschaffen wir:

  • Ein personPrototype-Objekt, das eine greet()-Methode besitzt.
  • Eine Person()-Konstruktorfunktion, die den Namen der zu erstellenden Person initialisiert.

Anschließend fügen wir die in personPrototype definierten Methoden mithilfe von Object.assign in die Prototype-Eigenschaft der Person-Funktion ein.

Nach diesem Code erhalten Objekte, die mit Person.prototype() erstellt wurden, als Prototyp die Methode greet, die automatisch die Methode greet enthält.

const reuben = new Person("Reuben");
reuben.greet(); // hello, my name is Reuben!

Dies erklärt auch, warum wir vorhin sagten, dass der Prototyp von myDate Date.prototype heißt: Dies ist die Prototyp-Eigenschaft des Date-Konstruktors.

Eigentum

Die Objekte, die wir mit dem oben genannten Person-Konstruktor erstellen, haben zwei Eigenschaften:

  • Eine Namenseigenschaft, die im Konstruktor festgelegt wird, sodass sie direkt in Person-Objekten erscheint.
  • Eine im Prototyp festgelegte greet()-Methode.

Dieses Muster ist weit verbreitet: Methoden werden im Prototyp definiert, Dateneigenschaften hingegen im Konstruktor. Der Grund dafür ist, dass die Methoden üblicherweise für jedes Objekt gleich sind, während wir oft möchten, dass jedes Objekt individuelle Werte für seine Dateneigenschaften besitzt (wie beispielsweise jeder Name einer Person).

Eigenschaften, die direkt im Objekt definiert sind, wie hier der Name, werden als eigene Eigenschaften bezeichnet. Ob eine Eigenschaft eine bestimmte Eigenschaft ist, kann mit der statischen Methode Object.hasOwn() überprüft werden:

const irma = new Person("Irma");
console.log(Object.hasOwn(irma, "name")); // true
console.log(Object.hasOwn(irma, "greet")); // false

Hinweis: Sie können hier auch die nicht-statische Methode Object.hasOwnProperty() verwenden, wir empfehlen jedoch, wenn möglich, Object.hasOwn() zu verwenden.

Prototypen und Vererbung

Prototypen sind ein leistungsstarkes und äußerst flexibles JavaScript-Feature, das die Wiederverwendung von Code und die Komposition von Objekten ermöglicht.

Sie unterstützen insbesondere eine Form der Vererbung. Vererbung ist ein Merkmal objektorientierter Programmiersprachen, das es Programmierern ermöglicht, auszudrücken, dass einige Objekte in einem System spezialisiertere Versionen anderer Objekte sind.

Wenn wir beispielsweise eine Schule modellieren, könnten wir Lehrer und Schüler haben: Beide sind Personen und teilen daher einige Eigenschaften (z. B. haben beide einen Namen). Jeder kann aber zusätzliche Eigenschaften hinzufügen (z. B. unterrichtet ein Lehrer ein bestimmtes Fach) oder dieselbe Eigenschaft auf unterschiedliche Weise implementieren. In einem objektorientierten System würden wir sagen, dass Lehrer und Schüler beide von der Klasse „Personen“ erben.

Sie können sehen, wie in JavaScript Professor- und Student-Objekte, wenn sie Person-Prototypen haben können, gemeinsame Eigenschaften erben können, während gleichzeitig Eigenschaften hinzugefügt und neu definiert werden können, die unterschiedlich sein müssen.

Im nächsten Artikel werden wir die Vererbung sowie weitere Kernmerkmale objektorientierter Programmiersprachen besprechen und sehen, wie JavaScript diese unterstützt.

Ergebnis

Dieser Artikel behandelt JavaScript-Objektprototypen, einschließlich der Frage, wie Objektprototypenketten es Objekten ermöglichen, Eigenschaften voneinander zu erben, der Prototyp-Eigenschaft und wie man sie verwendet, um Konstruktoren Methoden hinzuzufügen, sowie anderer verwandter Themen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Das könnte Ihnen auch gefallen