Ein gründliches Verständnis des JS-nativen Syntaxprototyps, des __proto__ und des Konstruktors

Ein gründliches Verständnis des JS-nativen Syntaxprototyps, des __proto__ und des Konstruktors

1 Einleitung

Ich habe ein paar Kommentare zum Vue-Quellcode geschrieben (keine Analyse ...) und hatte das Gefühl, dass mein Verständnis von Prototypen nicht ausreicht. In JS sind Prototypen sehr wichtig. Wenn Sie den JS-Berg erklimmen möchten, wird es Sie auslachen und sagen: „Haben Sie es herausgefunden?“ Wenn nicht, wird es Ihnen das Zehnfache an Schwerkraft verleihen. Wenn Sie es verstehen, können Sie definitiv mehr als 10.000 Yuan im Monat verdienen, eine schöne und reiche Frau gewinnen und den Höhepunkt Ihres Lebens erreichen ~~~


Dieser Artikel handelt von meinem eigenen Verständnis und sollte original sein (ich bin mir zu 99 % sicher, es sei denn, ich habe den Artikel schon einmal gelesen und kann ihn mir merken und kann kein Zitat angeben. Bitte kontaktieren Sie mich, damit ich es hinzufügen kann), aber wenn jemand auf meinen Artikel verweist, hoffe ich, einen Link zu diesem Artikel angeben zu können. Tatsächlich möchte ich nur, dass mein Artikel mehr Leser hat, ich möchte mehr als 10.000 Yuan im Monat verdienen, eine schöne und reiche Frau gewinnen und den Höhepunkt des Lebens erreichen~~~

2 Voraussetzungen

2.1 Datentypen

Es gibt 7 Datentypen in js

Je nachdem, ob die Attribute gelesen werden können oder nicht, können sie in zwei Kategorien unterteilt werden

  • Sie können Eigenschaften lesen:
    • Es kann Attribute haben: Objekt
    • Es darf keine Attribute haben: Zeichenfolge, Zahl, Boolescher Wert, Symbol
  • Eigenschaft kann nicht gelesen werden: null, undefiniert

Null, undefinierter Typ, Lesen und Setzen von Eigenschaften sind unzulässig und es wird direkt ein Fehler gemeldet.

Nur Objekte können eigene Eigenschaften haben und Eigenschaften lesen und setzen.

Die Typen Zeichenfolge, Zahl, Boolescher Wert und Symbol können Attribute lesen. Tatsächlich werden sie zuerst in ein Wrapper-Objekt eingebaut und dann werden die Attribute gelesen. Dasselbe gilt für das Setzen von Attributen. Es ist verständlich, dass, wenn die Attribute auf einem Wrapper-Objekt gesetzt werden, das sofort zerstört wird, sie gesetzt werden können, aber es gibt keine wesentlichen Auswirkungen.

2.2 Bestimmen Sie, ob es sich um eine eigene Eigenschaft handelt (hasOwnProperty)

Die Methode hasOwnProperty wird geerbt und dient dazu, zu bestimmen, ob das Objekt selbst diese Eigenschaft besitzt. Wenn dies der Fall ist, ist alles in Ordnung, unabhängig vom Wert.

const obj = { a: 1 }
const o = Objekt.erstellen(obj)
ob = 1
oc = ungültig 0
console.log('a', oa, o.hasOwnProperty('a')) // Kann den geerbten Wert lesen, aber nicht seine eigene Eigenschaft console.log('b', ob, o.hasOwnProperty('b')) // Kann den Wert lesen, seine eigene Eigenschaft console.log('c', oc, o.hasOwnProperty('c')) // Undefiniert lesen, seine eigene Eigenschaft console.log('d', od, o.hasOwnProperty('d')) // Undefiniert lesen, nicht seine eigene Eigenschaft und nicht von dieser Eigenschaft geerbt

3 Ein kleiner Gedanke

Programme sind Datenstrukturen und Algorithmen. Ein gutes Programm sollte zum Speichern der Daten möglichst wenig Speicher verwenden und den Vorgang so schnell wie möglich abschließen, um das Ergebnis zu erhalten.

Die Wiederverwendung von Daten kann den Speicherbedarf reduzieren. Wenn beispielsweise a und b dieselbe Funktion ausführen müssen, können sie dieselbe Methode (dasselbe Attribut) wiederverwenden.

Dann müssen wir ein Problem lösen: Wo existiert diese Wiederverwendungsmethode und wie können A und B sie finden.

Die Lösung in js besteht darin, dass sowohl a als auch b aus Funktionen konstruiert werden (nennen wir sie hier Funktionen) und die wiederverwendeten Methoden in der Funktion gespeichert werden (in der Prototype-Eigenschaft).

(Da nur der Konstruktor die wiederverwendete Methode speichern muss, existiert der Prototyp nur bei der konstruierbaren Funktion. Die Pfeilfunktion wird nicht zur Konstruktion verwendet und verfügt daher nicht über diese Eigenschaft. Andere Objekte verfügen nicht über diese Eigenschaft, sofern sie nicht einmal Funktionen sind.)

Dann müssen wir eine Verbindung zwischen a, b und Funktion herstellen, da a und b die Wiederverwendungsmethode finden müssen, die sie in der Funktion verwenden können.

Die Implementierung in js erfolgt über das Konstruktorattribut, dh a.constructor und b.constructor können Funktionen finden

Über a.constructor.prototype können wir also die Speicheradresse der wiederverwendbaren Methode finden. Um js schnell zu finden, wird eine Abkürzungsmethode a.__proto__ bereitgestellt, um es in einem Schritt zu finden, d. h. a.constructor.prototype und a.__proto__ finden dasselbe Objekt, also sind sie natürlich gleich.

// Keines von beiden ist eine eigene Eigenschaft. Ich weiß nicht, wie ich das Prototypobjekt anhand dieser beiden Eigenschaften finden kann. Das muss Magie sein...
const obj = {}
console.log(obj.hasOwnProperty('__proto__')) // falsch
console.log(obj.hasOwnProperty('Konstruktor')) // falsch

(Wenn Sie also die Zeiger von Konstruktor, Prototyp, __proto__ manuell ändern, müssen Sie wissen, was Sie tun.)

(Ich weiß nicht, ob die Designer von js so denken, haha, ich denke schon, so ist es viel einfacher zu verstehen)

(Dieser Vorgang wird Vererbung genannt und ist ein Kettenprozess, d. h. Sie können a.constructor.prototype.constructor.prototype.constructor.prototype durchsuchen, bis Sie die Spitze finden. Dieser Vorgang kann durch a.__proto__.__proto__.__proto__ beschleunigt werden. Dies wird als Prototypenkette bezeichnet. Dies ist die einzige Möglichkeit, Vererbung in js zu implementieren.)

(Das Obige dient nur als Leitfaden für den Denkprozess. Tatsächlich wird das Prototypobjekt nicht über a.constructor.prototype gefunden, sondern direkt über __proto__.)

3.1 Ändern des Konstruktors

const Hund = Funktion () {}
const Hund = neuer Hund()

Hund.Konstruktor = 0

console.log(dog.hasOwnProperty('Konstruktor')) // wahr
konsole.log(Hund.Konstruktor) // 0

console.log(dog.__proto__.constructor) // [Funktion: Hund]

Zusammenfassend lässt sich sagen, dass das Ändern dieser Eigenschaft die Schwierigkeit erhöht, den Konstruktor zu finden, der sie erstellt. Sie kann nicht direkt abgerufen werden und muss aus dem Prototypobjekt gelesen werden.

Wenn sowohl seine eigene Eigenschaft als auch die Eigenschaft des Prototyps geändert werden, kann lediglich sein Konstruktor nicht gefunden werden und es gibt keine weiteren Auswirkungen.

3.1.1 Instanz von

Instanceof befasst sich mit der Prototypenkette und hat nichts mit dem Konstruktor zu tun

Wenn Sie den obigen Punkt bestätigen, hat das Ändern des Konstruktorattributs keine anderen Auswirkungen, außer dass die Instanz ihren Konstruktor nicht finden kann. Wenn Sie ihren Konstruktor über die Instanz finden müssen, müssen Sie die Beziehung zwischen den beiden aufrechterhalten.

// Die Syntax ist // eine Instanz von b
// Dieser Operator bestimmt, ob in der Prototypenkette von a b.prototype vorhanden ist. Da b.prototype bestimmt werden muss, muss b eine konstruierbare Funktion sein, andernfalls wird ein Fehler gemeldet const fn = function () {}
const o = Objekt.erstellen(fn.prototype)
// Zu diesem Zeitpunkt gibt es fn.prototype in der Prototypenkette von o, weil o.__proto__ === fn.prototype
console.log(o Instanz von fn) // true
const leeresObj = {}
fn.prototype = leeresObjekt
// An diesem Punkt gibt es kein fn.prototype in der Prototypenkette von o, da o.__proto__ nicht mehr gleich fn.prototype ist console.log(o instanceof fn) // false
o.__proto__ = leeresObjekt
// Korrigieren Sie einfach o.__proto__ console.log(o instanceof fn) // true

3.1.2 istPrototypVon

Jetzt gibt es eine neue API, die die gleiche Funktionalität wie instanceof implementiert, aber semantischer ist und direkt bestimmt, ob sich ein Objekt in der Prototypenkette eines anderen Objekts befindet.

const fn = Funktion () {}
const o = Objekt.erstellen(fn.prototype)
console.log(fn.prototype.isPrototypeOf(o)) // wahr

3.2 Ändern Sie __proto__|prototype

Lassen Sie mich zunächst zusammenfassen. Beim Erstellen einer Instanz zeigt das __proto__ dieser Instanz zu diesem Zeitpunkt auf den Prototyp des Konstruktors, und dann erbt die Instanz tatsächlich __proto__. (Warum dieses Mal betonen, weil der Prototyp des Konstruktors geändert werden kann, um darauf zu zeigen, und die Änderung nur die nach der Änderung erstellte Instanz betrifft. Die vor der Änderung erstellte Instanz verwendet weiterhin den Prototyp vor der Änderung.)

Daher können Sie die Auswirkungen der Änderung von __proto__ und prototype verstehen.

1. Ändern Sie die Richtung von __proto__

Es betrifft nur sein eigenes Erbe

const Hund = Funktion () {}
const Hund = neuer Hund()
const d = neuer Hund()
Dog.prototype.name = "Hund"
Hund.__proto__ = {
  Name: '__proto__',
}
console.log(d.name) // Hund
console.log(Hundename) // __proto__

2. Ändern Sie die Eigenschaften von __proto__

Beispiele, die diese Bandstruktur beeinflussen

const Hund = Funktion () {}
const Hund = neuer Hund()
const d = neuer Hund()
Dog.prototype.name = "Hund"
console.log(d.name) // Hund
console.log(Hundename) // Hund
Hund.Prototyp = {
  Name: 'nach',
}
const hund1 = neuer Hund()
const d1 = neuer Hund()
console.log(d1.name) // danach
console.log(dog1.name) // danach
hund1.__proto__.name = "__proto__"
// Sie können sehen, dass nur die Instanz der aktuellen Konstruktion betroffen ist. Die vorherigen und nachfolgenden Instanzen sind nicht betroffen, da dieser Abschnitt denselben Dog.prototype enthält und ihre __proto__ alle darauf verweisen console.log(d1.name) // __proto__
console.log(hund1.name) // __proto__
Hund.Prototyp = {
  Name: "neu",
}
const hund2 = neuer Hund()
const d2 = neuer Hund()
console.log(d2.name) // neu
console.log(dog2.name) // neu

3. Ändern Sie die Richtung des Prototyps

Beispiele, die diese Bandstruktur beeinflussen

4. Ändern Sie die Eigenschaften des Prototyps

Es wirkt sich auf die Instanz dieser Bandstruktur aus, genau wie das Ändern der Eigenschaft __proto__

4 So ändern und erhalten Sie Prototypobjekte

4.1 Änderungen

Wir haben bereits die Modifizierung von prototype und __proto__ besprochen.

4.1.1 Objekt.erstellen

const obj = {
  Name: "Objektname",
}

const o = Objekt.erstellen(obj)
// Es ist gleichwertig mit o.__proto__ = obj, es wird jedoch empfohlen, „Object.create“ zu verwenden.

console.log(o.name) // Objektname
console.log(o.__proto__ === obj) // wahr

4.1.2 Objekt.setPrototypeOf

const obj = {
  Name: "Objektname",
}

const o = {}

Objekt.setPrototypeOf(o, obj)
// Es ist gleichwertig mit o.__proto__ = obj, es wird jedoch empfohlen, „Object.setPrototypeOf“ zu verwenden.
const proto = Object.getPrototypeOf(o)
konsole.log(proto === obj && proto === o.__proto__) // wahr
const obj1 = {}
o.__proto__ = obj1
const proto1 = Object.getPrototypeOf(o)
console.log(proto1 === obj1 && proto1 === o.__proto__) // wahr

Zusammenfassend: Wann sollten wir Object.create und wann Object.setPrototypeOf verwenden? Zunächst einmal sind beides Standard-APIs und werden empfohlen. Wenn Sie beim Erstellen eines Objekts einen Prototyp angeben müssen, verwenden Sie Object.create. Wenn Sie das Prototypobjekt dynamisch ändern müssen, verwenden Sie Object.setPrototypeOf.

4.2 Erwerb

Wie bereits erwähnt, erhalten wir es durch constructor.prototype und __proto__

4.2.1 Objekt.getPrototypeOf

const obj = {
  Name: "Objektname",
}

const o = {}

Objekt.setPrototypeOf(o, obj)

const proto = Object.getPrototypeOf(o)
konsole.log(proto === obj && proto === o.__proto__) // wahr

5 js integrierter nativer Konstruktor

Die Prototypeigenschaft dieser nativen Konstruktoren ist nicht beschreibbar, nicht aufzählbar und nicht konfigurierbar.

Konsole.log(Objekt.getOwnPropertyDescriptor(Objekt, 'Prototyp'))
// {
// Wert: [Objekt: Null-Prototyp] {},
// beschreibbar: false,
// aufzählbar: false,
// konfigurierbar: false
// }

5.1 Was ist die oberste Ebene der JS-Vererbung?

null, es muss dieser Typ sein, sonst können wir es nur unendlich machen

Dann werden alle anderen Objekte aus Object konstruiert, sodass alle Objekte von Object.prototype erben können.

const obj = {}
const o = neues Objekt()

5.2 js erbt Bürger zweiter Klasse (Funktion)

In den obigen kurzen Überlegungen wurde erwähnt, dass JS-Objekte aus Funktionen konstruiert werden, sodass Objekte ebenfalls aus Funktionen konstruiert werden und sogar Objekte selbst aus sich selbst konstruiert werden.

konsole.log(Objekt.Konstruktor === Funktion) // true
// Das ist lächerlich, woher kommt die erste Funktion????
konsole.log(Funktion.Konstruktor === Funktion) // wahr

Lassen Sie mich Ihnen das etwas näher bringen. Vielleicht werden einige Verarbeitungsvorgänge innerhalb von js durchgeführt. Die erste Funktion wird aus dem Nichts erstellt. Dann erstellt diese Funktion ein Objekt, und dann erstellt dieses Objekt das erste Prototypobjekt Object.prototype, und dann werden einige Referenzbeziehungen geändert.

Tatsächlich ist die Beziehung zwischen Objekt und Funktion das Komplizierteste

konsole.log(Objekt.__proto__ === Funktion.prototyp) // wahr
konsole.log(Funktion.Konstruktor === Funktion) // wahr
Konsole.log(Funktion.__proto__ === Funktion.prototyp) // wahr
Konsole.log(Funktion.prototype.__proto__ === Objekt.prototype) // wahr

5.3 js erbt Bürger dritter Klasse (andere integrierte Konstruktoren)

Konstanten arr = [
  Schnur,
  Anordnung,
  Boolesch,
  Nummer,
  Datum,
  Regulärer Ausdruck,
  Fehler,
  Versprechen,
  Karte,
  Satz,
  Symbol,
  Stellvertreter,
]
// Alle sind aus der Funktion aufgebaut

6 Benutzerdefinierte spezielle Bürgerkonstruktoren

Dies ist der entscheidende Punkt. Basierend auf dem obigen Verständnis werde ich einen weiteren Artikel über mein Verständnis der JS-Vererbung schreiben. Ich werde hier vorerst eine Lücke lassen.

7. Fazit

Dieser Artikel unterscheidet sich von den meisten Artikeln im Internet, in denen es um Konstruktoren, Prototypen und __proto__ geht. Mein Ausgangspunkt ist, von einem gegebenen Wert auszugehen, der eine Eigenschaft lesen kann. In js können außer null und undefiniert alle anderen Werte ein Ausgangspunkt sein. Von diesem Ausgangspunkt aus zeichnet seine __proto__-Eigenschaft sein Prototypobjekt auf, das der Wert der Prototypeigenschaft seines Konstruktors ist, wenn es erstellt wird.

Konstante a = 1
console.log(a.__proto__.constructor) // [Funktion: Zahl]

Wenn beim Lesen des Wertes einer Eigenschaft eines Wertes diese Eigenschaft selbst vorhanden ist, wird der Wert dieser Eigenschaft direkt zurückgegeben. Andernfalls wird zu seinem __proto__-Objekt gegangen, um es zu finden, und rekursiv weitergemacht, bis es das oberste Null findet. Wenn es es findet, wird sein Wert zurückgegeben, andernfalls wird undefiniert zurückgegeben.

In diesem Artikel gibt es drei Erkenntnisse, die mir plötzlich ein Licht aufgingen. Es sind alles Schlussfolgerungen, zu denen ich nach einer langen Zeit des Experimentierens plötzlich gelangt bin.

  1. Beginnen Sie Ihre Analyse mit einem Wert als Ausgangspunkt
  2. Beim Erstellen einer Instanz verweist die Instanz __proto__ auf den Prototyp des Konstruktors zu diesem Zeitpunkt.
  3. Bei der Suche nach einem Prototypobjekt wird __proto__ als Grundlage verwendet

8. Zuletzt

Dies ist das Ende dieses Artikels über den nativen Syntaxprototyp von JS, __proto__ und den Konstruktor. Weitere relevante Inhalte zum nativen Syntaxprototyp von JS, __proto__ und dem Konstruktor finden Sie in den vorherigen Artikeln von 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:
  • Javascript-Prototyp
  • Details zum JavaScript-Prototyp
  • isPrototypeOf-Funktion in JavaScript
  • JavaScript verwendet die Prototype-Eigenschaft, um Vererbungsoperationen zu implementieren. Beispiel
  • Implementierung der Dimensionsreduzierung von JS-Arrays Array.prototype.concat.apply([], arr)
  • Erweiterung des js String.prototype.trim-Zeichens zum Entfernen führender und nachfolgender Leerzeichen
  • JavaScript __proto__ und Prototyp

<<:  Schritt-für-Schritt-Anleitung zur Installation von VMware Workstation und des Betriebssystems WIN10 zur Verbindung mit dem externen Netzwerk (sehr ausführliches Tutorial)

>>:  Detaillierte Erläuterung der drei Möglichkeiten zum Importieren von CSS-Dateien

Artikel empfehlen

Detaillierte Erklärung des JavaScript-Fortschrittsmanagements

Inhaltsverzeichnis Vorwort Frage Prinzip prüfen V...

Warum wird UTF-8 in MySQL nicht empfohlen?

Ich bin kürzlich auf einen Fehler gestoßen, als i...

Docker- und Portainer-Konfigurationsmethoden unter Linux

1. Installieren und verwenden Sie Docer CE Dieser...

Detaillierte Erklärung der Getter-Verwendung in vuex

Vorwort Mit Vuex können wir im Store „Getter“ def...

MySQL-Sequenz AUTO_INCREMENT ausführliche Erklärung und Beispielcode

MySQL-Sequenz AUTO_INCREMENT ausführliche Erkläru...

Detaillierte Erklärung des Unterschieds zwischen Flex und Inline-Flex in CSS

inline-flex ist dasselbe wie inline-block. Es ist...

JS praktisches objektorientiertes Schlangenspielbeispiel

Inhaltsverzeichnis denken 1. Bild mit dem gierige...

So lösen Sie das Problem, dass der Docker-Container keinen Vim-Befehl hat

Finden Sie das Problem Als ich heute versuchte, d...