Ein Artikel, der Ihnen hilft, die Vererbung und Prototypenkette von JS zu verstehen

Ein Artikel, der Ihnen hilft, die Vererbung und Prototypenkette von JS zu verstehen

Vererbung und Prototypenkette

Wenn es um Vererbung geht, hat JavaScript nur eine Konstruktion: das Objekt. Jedes Instanzobjekt verfügt über eine private Eigenschaft (Proto genannt), die auf das Prototypobjekt seines Konstruktors verweist. Das Prototypobjekt hat auch sein eigenes Prototypobjekt (Proto), Schicht für Schicht, bis das Prototypobjekt eines Objekts null ist. Per Definition hat null keinen Prototyp und dient als letztes Glied in dieser Prototypenkette.

Fast alle Objekte in JavaScript sind Instanzen von Object, das sich am oberen Ende der Prototypenkette befindet.

Geerbte Eigenschaften

JavaScript-Objekte sind dynamische „Säcke“ mit Eigenschaften (die sich auf ihre eigenen Eigenschaften beziehen). JavaScript-Objekte haben einen Link zu einem Prototypobjekt. Wenn Sie versuchen, auf eine Eigenschaft eines Objekts zuzugreifen, wird nicht nur im Objekt selbst, sondern auch im Prototyp des Objekts und im Prototyp des Prototyps des Objekts usw. gesucht, bis eine Eigenschaft mit passendem Namen gefunden wird oder das Ende der Prototypenkette erreicht wird.

Codebeispiel

Funktion fn() {
  dies.a = 1;
  dies.b = 2;
}

const o = neue fn();

fn.prototype.b = 3;
fn.prototype.c = 4;
Konsole.log(oa);
console.log(ob);
konsole.log(oc);
konsole.log(od);
// 1
// 2
// 4
// undefiniert
  • a und b sind Eigenschaften von o und können Werte direkt zurückgeben
  • Warum setzen wir fn.prototype.b = 3, aber der zurückgegebene Wert ist immer noch 2? Denn wenn wir dieses Attribut in uns selbst suchen, geben wir es direkt zurück und suchen nicht oben danach.
  • Da c kein Attribut von o ist, wird in o.prototype danach gesucht und wenn c gefunden wird, wird der Wert direkt zurückgegeben.
  • d ist kein Attribut von o, daher wird es auf o.prototype gesucht. Wenn es nicht gefunden wird, wird es auf o.protype.prototype gesucht. Wenn es null ist, wird die Suche abgebrochen und „undefined“ zurückgegeben.

Schauen Sie sich den Ausdruck des o-Konstruktors an

{
    ein: 1
    b: 2
    __proto__:
        b: 3
        c: 4
        Konstruktor: ƒ fn()
        __proto__:
            Konstruktor: ƒ Object()
            hatEigeneEigenschaft: ƒ hatEigeneEigenschaft()
            istPrototypVon: ƒ istPrototypVon()
            propertyIsEnumerable: ƒ propertyIsEnumerable()
            toLocaleString: ƒ toLocaleString()
            toString: ƒ toString()
            Wert von: ƒ Wert von ()
            __defineGetter__: ƒ __defineGetter__()
            __defineSetter__: ƒ __defineSetter__()
            __lookupGetter__: ƒ __lookupGetter__()
            __lookupSetter__: ƒ __lookupSetter__()
            bekomme __proto__: ƒ __proto__()
            setze __proto__: ƒ __proto__()
}

Geerbte Methoden

JavaScript hat keine „Methoden“, wie andere klassenbasierte Sprachen sie definieren. In JavaScript kann einem Objekt jede beliebige Funktion als Eigenschaft des Objekts hinzugefügt werden. Die Funktionsvererbung unterscheidet sich nicht von der Vererbung anderer Eigenschaften, einschließlich der oben erwähnten „Eigenschaftsverschattung“ (die dem Überschreiben von Methoden in anderen Sprachen entspricht).

Wenn eine geerbte Funktion aufgerufen wird, bezieht sich dies auf das aktuelle geerbte Objekt und nicht auf das Prototypobjekt, in dem sich die geerbte Funktion befindet.

var o = {
  eine: 2,
  m: Funktion () {
    gib dies zurück.a + 1;
  },
};

console.log(om()); // 3
// Beim Aufruf von om bezieht sich „this“ auf o.

var p = Objekt.create(o);
// p ist ein Objekt, das von o erbt pa = 4; // Erstelle ps eigenes Attribut „a“
konsole.log(pm()); // 5
// Beim Aufruf von pm zeigt 'this' auf p
// Und weil p die m-Funktion von o erbt, // ist daher 'this.a', also pa, ps eigenes Attribut 'a'

Verwenden von Prototypen in JavaScript

In JavaScript dürfen Funktionen Eigenschaften haben. Alle Funktionen haben eine spezielle Eigenschaft namens Prototyp. Standardmäßig ist es das Prototypobjekt von Object

Funktion tuEtwas() {}
Konsole.log(mache etwas.Prototyp);
// Es hat nichts damit zu tun, wie die Funktion deklariert wird.
//Funktionen in JavaScript haben immer eine Standard-Prototyp-Eigenschaft.
var tuEtwas = Funktion () {};
Konsole.log(mache etwas.Prototyp);

Im in der Konsole angezeigten JavaScript-Codeblock sehen wir einen Standardeigenschaftsprototyp für die Funktion doSomething. Nach dem Ausführen dieses Codes sollte die Konsole ähnliche Ergebnisse wie die folgenden anzeigen:

{
    Konstruktor: ƒ doSomething(),
    __proto__: {
        Konstruktor: ƒ Object(),
        hatEigeneEigenschaft: ƒ hatEigeneEigenschaft(),
        istPrototypeOf: ƒ istPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        Wert von: ƒ Wert von ()
    }
}

Wir können dem Prototypobjekt der Funktion doSomething wie folgt neue Eigenschaften hinzufügen:

Funktion tuEtwas() {}
doSomething.prototype.foo = "Leiste";
Konsole.log(mache etwas.Prototyp);

Sie können die Ergebnisse nach dem Ausführen wie folgt sehen:

{
    foo: "Leiste",
    Konstruktor: ƒ doSomething(),
    __proto__: {
        Konstruktor: ƒ Object(),
        hatEigeneEigenschaft: ƒ hatEigeneEigenschaft(),
        istPrototypeOf: ƒ istPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        Wert von: ƒ Wert von ()
    }
}

Jetzt können wir den neuen Operator verwenden, um eine Instanz von doSomething basierend auf diesem Prototypobjekt zu erstellen.

Code:

Funktion tuEtwas() {}
doSomething.prototype.foo = "bar"; // füge dem Prototyp eine Eigenschaft hinzu
var doSomeInstancing = neues doSomething();
doSomeInstancing.prop = "irgendein Wert"; // füge dem Objekt eine Eigenschaft hinzu
console.log(macheEinigeInstanz);

Das Ergebnis der Ausführung ähnelt der folgenden Anweisung.

{
    Requisite: „ein gewisser Wert“,
    __proto__: {
        foo: "Leiste",
        Konstruktor: ƒ doSomething(),
        __proto__: {
            Konstruktor: ƒ Object(),
            hatEigeneEigenschaft: ƒ hatEigeneEigenschaft(),
            istPrototypeOf: ƒ istPrototypeOf(),
            propertyIsEnumerable: ƒ propertyIsEnumerable(),
            toLocaleString: ƒ toLocaleString(),
            toString: ƒ toString(),
            Wert von: ƒ Wert von ()
        }
    }
}

Wir können sehen, dass prop die Eigenschaft von doSomeInstancing selbst ist und proto in doSomeInstancing doSomething.prototype ist.

Wir drucken die Eigenschaften innen

console.log("doSomeInstancing.prop: " + doSomeInstancing.prop);
console.log("doSomeInstancing.foo: " + doSomeInstancing.foo);
console.log("macheSomething.prop: " + macheSomething.prop);
console.log("macheEtwas.foo: " + macheEtwas.foo);
console.log("macheSomething.prototype.prop: " + macheSomething.prototype.prop);
console.log("macheSomething.prototype.foo: " + macheSomething.prototype.foo);

Die Ergebnisse sind wie folgt:

// Die eigenen Eigenschaften von doSomeInstancing geben den Wert direkt zurück doSomeInstancing.prop: some value
// Es ist keine Eigenschaft von doSomeInstancing selbst. Überprüfen Sie das Prototypobjekt und stellen Sie fest, dass es diese Eigenschaft gibt, die direkt den Wert doSomeInstancing.foo: bar zurückgibt.
// Es ist weder eine Eigenschaft der Funktion selbst, noch eine Eigenschaft des Prototypobjekts. Wenn wir Schicht für Schicht nach oben suchen und schließlich feststellen, dass der Prototyp null ist, bedeutet dies, dass es keine solche Eigenschaft gibt. Daher geben wir undefined zurück.
doSomething.prop: nicht definiert
doSomething.foo: nicht definiert
doSomething.prototype.prop: nicht definiert
// Finde das Prototypobjekt von doSomething und es hat die Eigenschaft foo, also gib direkt den Wert doSomething.prototype.foo zurück: bar

Leistung

Das Nachschlagen von Eigenschaften in der Prototypenkette ist zeitaufwändig und wirkt sich negativ auf die Leistung aus, was in leistungskritischen Situationen wichtig ist. Darüber hinaus durchlaufen Versuche, auf nicht vorhandene Eigenschaften zuzugreifen, die gesamte Prototypenkette.

Beim Durchlaufen der Eigenschaften eines Objekts wird jede aufzählbare Eigenschaft in der Prototypkette aufgezählt. Um zu überprüfen, ob ein Objekt eine Eigenschaft hat, die es selbst definiert, und nicht eine Eigenschaft in seiner Prototypenkette, müssen Sie die Methode hasOwnProperty verwenden, die alle Objekte von Object.prototype erben. Hier ist ein konkretes Beispiel zur Veranschaulichung:

console.log(doSomeInstancing.hasOwnProperty("prop"));
// WAHR

console.log(doSomeInstancing.hasOwnProperty("bar"));
// FALSCH

console.log(doSomeInstancing.hasOwnProperty("foo"));
// FALSCH

console.log(doSomeInstancing.__proto__.hasOwnProperty("foo"));
// WAHR

hasOwnProperty ist die einzige Methode in JavaScript, die sich mit Eigenschaften befasst und nicht die Prototypenkette durchläuft.

Eine weitere solche Methode: Object.keys()

Hinweis: Durch die Überprüfung, ob eine Eigenschaft nicht definiert ist, können Sie nicht feststellen, ob sie existiert. Die Eigenschaft ist möglicherweise bereits vorhanden, ihr Wert ist jedoch zufällig auf „undefiniert“ eingestellt.

Anhang: Die Prototypenkette ist die Hauptmethode zur Erzielung von Vererbung

Lassen Sie uns zunächst über Vererbung sprechen. Viele OO-Sprachen unterstützen zwei Vererbungsmethoden: Schnittstellenvererbung und Implementierungsvererbung.

|- Schnittstellenvererbung: nur Methodensignaturen erben

|- Implementierungsvererbung: Vererbung tatsächlicher Methoden

Da Funktionen keine Signaturen haben, kann die Schnittstellenvererbung in ECMAScript nicht implementiert werden. Es wird nur die Implementierungsvererbung unterstützt, und die Implementierungsvererbung wird hauptsächlich über die Prototypenkette erreicht.

Die Grundidee der Prototypkette:

Verwenden Sie Prototypen, um einen Referenztyp die Eigenschaften und Methoden eines anderen Referenztyps erben zu lassen.

Jeder Konstruktor hat ein Prototypobjekt, das einen Zeiger auf den Konstruktor (Konstruktor) enthält, und das Instanzobjekt enthält einen internen Zeiger auf das Prototypobjekt (__proto__). Wenn Sie das Prototypobjekt einer Instanz eines anderen Typs gleichsetzen, enthält das Prototypobjekt einen Zeiger auf einen anderen Prototyp (__proto__), und der andere Prototyp enthält auch einen Zeiger auf eine andere Konstruktorfunktion (Konstruktor). Wenn ein anderer Prototyp eine Instanz eines anderen Typs ist, … bildet dies eine Kette von Instanzen und Prototypen.

Die Grundidee der Prototypkette (Diagramm):

Zusammenfassen

Dies ist das Ende dieses Artikels über Js-Vererbung und Prototypenkette. Weitere relevante Inhalte zu Js-Vererbung und Prototypenkette finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • Kennen Sie Javascript-Prototypen und Prototypenketten?
  • Wie gut kennen Sie sich mit dem Konstruktor, Prototyp, der Prototypenkette und Neuem von JavaScript aus?
  • Zusammenfassung und Praxis des Javascript-Prototyp-Kettendiagramms
  • Tiefgreifendes Verständnis von Javascript-Prototypen und Prototypenketten
  • Zwei Bilder von JavaScript zum Verständnis der Prototypenkette
  • Detaillierte Erläuterung des JavaScript-Prototyps und der Prototypenkette

<<:  Das kürzeste JS, um festzustellen, ob es sich um IE6 handelt (IE-Schreibmethode)

>>:  Tiefgreifendes Verständnis der Probleme mit der Transaktionsisolationsebene und dem Sperrmechanismus von MySQL

Artikel empfehlen

Die perfekte Lösung für das MySql-Versionsproblem sql_mode=only_full_group_by

1. Überprüfen Sie sql_mode wählen Sie @@sql_mode ...

Methoden zum Defragmentieren und Freigeben von Speicherplatz in MySQL-Tabellen

Inhaltsverzeichnis Ursachen der MySQL-Tabellenfra...

JavaScript zur Implementierung des Anmeldeformulars

In diesem Artikelbeispiel wird der spezifische Ja...

Ein Artikel zum Umgang mit Mysql-Datums- und Zeitfunktionen

Inhaltsverzeichnis Vorwort 1. Aktuelle Uhrzeit er...

Detaillierte Erklärung gängiger Befehle in MySQL 8.0+

Aktivieren Sie den Fernzugriff Aktivieren Sie die...

Implementierung von webpack-dev-server zum Erstellen eines lokalen Servers

Inhaltsverzeichnis Vorwort Webpack-Deb-Server Sta...

Verwendung von Umgebungsvariablen in Docker und Lösungen für häufige Probleme

Vorwort Docker kann Umgebungsvariablen für Contai...

Drei häufig verwendete MySQL-Datentypen

Das Definieren des Datenfeldtyps in MySQL ist für...

Der Unterschied zwischen shtml und html

Shtml und asp sind ähnlich. In Dateien mit dem Nam...

Vue + node realisiert Audioaufzeichnungs- und -wiedergabefunktion

Ergebnis: Der Hauptteil besteht darin, die Codelo...

Mysql gibt die Methode zur Datumsbereichsextraktion an

Bei der Datenbankoperation ist der Umgang mit Dat...