Verstehen Sie JavaScript-Prototypen und Prototypenketten gründlich

Verstehen Sie JavaScript-Prototypen und Prototypenketten gründlich

Vorwort

Das Wissen über Prototypen und Prototypenketten stand bei Interviews immer im Mittelpunkt. Es ist nicht allzu schwierig, aber es erfordert dennoch einige Anstrengung, es vollständig zu verstehen. Um Ihr Interesse zu wecken, werfen wir einen Blick auf eine Interviewfrage:

Funktion Benutzer() {}
Benutzer.prototype.sayHello = Funktion() {}
var u1 = neuer Benutzer();
var u2 = neuer Benutzer();
Konsole.log(u1.sayHello === u2.sayHello); 
console.log(Benutzer.Prototyp.Konstruktor); 
console.log(Benutzer.prototyp === Funktion.prototyp); 
console.log(Benutzer.__proto__ === Funktion.prototyp); 
console.log(Benutzer.__proto__ === Funktion.__proto__); 
Konsole.log(u1.__proto__ === u2.__proto__); 
console.log(u1.__proto__ === Benutzer.__proto__); 
Konsole.log(Funktion.__proto__ === Objekt.__proto__); 
Konsole.log(Funktion.prototype.__proto__ === Objekt.prototype.__proto__); 
Konsole.log(Funktion.prototype.__proto__ === Objekt.prototype); 

Den Grundstein legen

Alle JavaScript-Objekte werden grundsätzlich durch die neue Funktion erstellt, einschließlich Objekte, die in Form von Objektliteralen definiert sind (entspricht dem syntaktischen Zucker von new Object()).

Alle Funktionen werden grundsätzlich über eine neue Funktion erstellt, einschließlich Objekt, Array usw.

Alle Funktionen sind Objekte.

Prototyp

Jede Funktion hat einen Eigenschaftsprototyp, der den Prototyp darstellt. Standardmäßig ist es ein gewöhnliches Object-Objekt, das der Prototyp der durch Aufruf des Konstruktors erstellten Instanz ist.

Konstruktor-Eigenschaften

JavaScript hat auch eine Eigenschaft, die auf den Konstruktor vom Prototyp verweist: Konstruktor, d. h. Func.prototype.constructor --> Func

__proto__

Alle Objekte in JavaScript (außer null) haben eine __proto__-Eigenschaft, die auf den Prototyp des Objekts verweist.

Funktion Benutzer() {}
var u1 = neuer Benutzer();
// u1.__proto__ -> Benutzer.prototyp
console.log(u1.__proto__ === Benutzer.prototyp) // wahr

Offensichtlich verweist die __proto__-Eigenschaft der Instanz auf den Prototyp des Konstruktors. Verweist also das __proto__ mehrerer Instanzen auf denselben Prototyp?

var u2 = neuer Benutzer();
console.log(u1.__proto__ === u2.__proto__) // wahr

Wenn alle __proto__ mehrerer Instanzen auf den Prototyp des Konstruktors verweisen und die Instanzen auf eine bestimmte Weise auf die Methoden, Eigenschaften usw. des Prototyps zugreifen können, können sie auf dem Prototyp programmieren und den Effekt der Vererbung erzielen.

Lassen Sie uns weiterhin das Beziehungsdiagramm zwischen Prototypen und Prototypketten aktualisieren:

Prototypenkette

Wenn ein Instanzobjekt nach einem Attribut sucht und es nicht finden kann, folgt es __proto__, um nach dem mit dem Objekt verknüpften Prototyp zu suchen. Wenn es ihn immer noch nicht finden kann, sucht es nach dem Prototyp des Prototyps, bis es die oberste Ebene findet. Dies ist das Konzept der Prototypenkette.

Schauen wir uns einige Beispiele für Prototypketten anhand von Interviewfragen an:

Beispiel

  1. u1.sayHello():
    Es gibt keine sayHello-Methode auf u1, also greifen Sie auf u1.__proto__(User.prototype) zu und greifen Sie erfolgreich auf die sayHello-Methode zu
  2. u2.toString()
    u2, User.prototype hat keine toString-Methode und User.prototype ist auch ein normales Objekt. Daher suchen wir weiter nach User.prototype.__proto__(Object.prototype) und rufen die toString-Methode erfolgreich auf.

verbessern

Nachdem Sie das oben Gesagte gelernt haben, können die meisten Interviewfragen beantwortet werden, wie zum Beispiel die folgenden

Funktion A() {}
Funktion B(a) {
    dies.a = a;
}
Funktion C(a) {
    wenn (a) {
        dies.a = a;
    }
}
A.Prototyp.a = 1;
B.prototyp.a = 1;
C.prototyp.a = 1;

konsole.log(neu A().a); //1
console.log(new B().a); //undefiniert
konsole.log(neu C(2).a); //2

Es fehlt jedoch noch etwas zur Lösung der ursprünglichen Interviewfragen im Artikel, wie z. B. Function.__proto__ === Object.__proto__, Function.prototype.__proto__ === Object.prototype.__proto__ usw. Lassen Sie uns diese nacheinander angehen.

Objekt.__proto__ , Objekt.prototype, Objekt.prototype.__proto__

  • Object ist der Konstruktor. Im zweiten Teil haben wir gesagt, dass alle Funktionen über eine neue Funktion erstellt werden, sodass Object einer Instanz von Function entspricht, d. h. Object.__proto__ --> Function.prototype.
  • Object.prototype ist der Prototyp des Objektkonstruktors, der sich am Anfang der Prototypenkette befindet. Object.prototype.__proto__ hat keinen oberen Prototypen, auf den es verweisen kann, daher ist sein Wert null.
// Zusammenfassen:
Objekt.__proto__ --> Funktion.prototype
Objekt.prototype.__proto__ --> null

Funktion.__proto__, Funktion.prototyp, Funktion.prototyp.__proto__

  • Function.prototype ist der Prototyp der Funktion, der wiederum der Prototyp aller Funktionsinstanzen ist, wie beispielsweise das oben erwähnte Object.__proto__.
  • Function.prototype ist ein normales Objekt, also Function.prototype.__proto__ --> Object.prototype
  • Function.__proto__: __proto__ zeigt auf den Prototyp des Konstruktors, der es erstellt hat. Wer hat also Function erstellt?
    • Hypothese: Funktionsobjekte sind auch Objekte. Wird Function.__proto__ also auf Object.prototype verweisen? Wie oben erwähnt, Object.__proto__ --> Function.prototype. Wenn Function.__proto__ -> Object.prototype, ist es immer ein komisches Gefühl, wer wen erstellt hat, also habe ich ein paar Tests durchgeführt:

Die Praxis zeigt, dass es nur Object.__proto__ --> Function.prototype gibt

Ich habe lange nachgedacht, bin aber zu keinem Ergebnis gekommen. Könnte es sein, dass Function ein Affe ist, der zwischen den Felsen hervorspringt? Ich habe also eine Reihe von Tests durchgeführt und unerwartet einen Hinweis gefunden.

Aus dem Obigen können wir schließen: Function.__proto__ --> Function.prototype

Die Funktion wird durch nichts erstellt und wird dem Speicher hinzugefügt, wenn die JS-Engine gestartet wird.

Zusammenfassen

Abschließend werden die Erkenntnisse über Prototypen und Prototypenketten in einem Bild verdichtet:

  1. Das __proto__ aller Funktionen (einschließlich Function) verweist auf Function.prototype
  2. Das __proto__ einer benutzerdefinierten Objektinstanz verweist auf den Prototyp des Konstruktors
  3. Das __proto__ des Prototyps der Funktion zeigt auf Object.prototype
  4. Objekt.prototype.__proto__ --> null

Nachwort

Der Ozean des Wissens ist oft größer, als man denkt. Ich habe Prototypen und Prototypenketten viele Male studiert und denke, dass ich sie umfassender und vollständiger gelernt habe. Aber als ich auf diese Interviewfrage stieß, wurde mir klar, dass das, was ich gelernt hatte, nur ein Zweig war und dass es in JS wirklich viele tiefe Schätze gibt, die darauf warten, ausgegraben zu werden. Das Lernen hat kein Ende, lasst uns einander ermutigen.

Zum Schluss noch eine einfache Interviewfrage, die Ihr Selbstvertrauen stärkt:

var F = Funktion () {}
Objekt.prototype.a = Funktion () {}
Funktion.prototype.b = Funktion () {}

var f = neues F();

Konsole.log(fa, fb, Fa, Fb);

// Prototypenkette // f.__proto__ --> F.prototype --> Object.prototype
// F.__proto__ --> Funktion.prototyp --> Objekt.prototyp

Dies ist das Ende dieses Artikels über JavaScript-Prototypen und Prototypenketten. Weitere relevante Inhalte zu JavaScript-Prototypen und Prototypenketten 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:
  • Detaillierte Erklärung von Prototypen und Prototypenketten in JavaScript
  • Detaillierte Erklärung der JavaScript-Prototypenkette
  • Details zum JavaScript-Prototyp und zur Prototypkette
  • Umfassende Analyse von Prototypen, Prototypobjekten und Prototypketten in js
  • Tiefgreifendes Verständnis von Javascript-Prototypen und Prototypenketten

<<:  CSS-Standard: Eigenschaft „vertical-align“

>>:  Analyse des Consul-Konfigurationsprozesses für die Docker-Bereitstellung

Artikel empfehlen

Elemente der Benutzererfahrung oder Elemente des Webdesigns

System- und Benutzerumgebungsdesign <br />D...

Confluence mit Docker bereitstellen

1. Umweltanforderungen 1. Docker 17 und höher wur...

Lernen Sie, benutzerdefinierte Hooks in React zu erstellen

1. Was sind benutzerdefinierte Hooks Wiederverwen...

Detaillierte Anwendungsfälle von Vue3 Teleport

Offizielle Website https://cli.vuejs.org/en/guide...

Rückgängigmachen der Anmeldung in MySQL

Konzepteinführung: Wir wissen, dass das Redo-Log ...

Detaillierte Erklärung der atomaren DDL-Syntax von MySQL 8.0

Inhaltsverzeichnis 01 Einführung in Atomic DDL 02...

Beispiel zum Referenzieren von Umgebungsvariablen in Docker Compose

In einem Projekt müssen Sie häufig Umgebungsvaria...

Untersuchung des Problems der Flip-Navigation mit geneigter Maus

In diesem Artikel analysieren wir als Beispiel die...

Nginx Reverse Proxy Springboot JAR-Paket-Prozessanalyse

Die übliche Methode zum Bereitstellen eines Sprin...

Einführung in /etc/my.cnf-Parameter in MySQL 5.7

Nachfolgend finden Sie einige allgemeine Paramete...

Beispiele für die MySQL-Verschlüsselung und -Entschlüsselung

Beispiele für die MySQL-Verschlüsselung und -Ents...

Teilen Sie das Problem, dass Ubuntu 19 die Docker-Quelle nicht installieren kann

Entsprechend den wichtigsten Websites und persönl...