Ich mag keine dynamischen Programmiersprachen, aber ich habe meinen fairen Anteil an JavaScript-Code geschrieben. Ich habe mich nie wirklich mit dieser prototypbasierten Programmierung beschäftigt. Weiß jemand, wie das funktioniert?
var obj = new Object();
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();
Ich erinnere mich an viele Diskussionen, die ich vor einiger Zeit mit Leuten geführt habe (ich bin mir nicht ganz sicher, was ich tue), aber so wie ich es verstehe, gibt es kein Konzept für eine Klasse. Es ist nur ein Objekt, und Instanzen dieser Objekte sind Klone des Originals, oder?
Aber was genau ist der Zweck dieser ".prototype" -Eigenschaft in JavaScript? Wie hängt es mit der Instanziierung von Objekten zusammen?
Update: richtiger Weg
var obj = new Object(); // not a functional object
obj.prototype.test = function() { alert('Hello?'); }; // this is wrong!
function MyObject() {} // a first class functional object
MyObject.prototype.test = function() { alert('OK'); } // OK
Auch diese Folien haben sehr geholfen.
javascript
dynamic-languages
prototype-oriented
John Leidegren
quelle
quelle
Antworten:
Jedes JavaScript-Objekt hat einen internen "Slot" ,
[[Prototype]]
dessen Wert entwedernull
oder ein istobject
. Sie können sich einen Slot als eine Eigenschaft eines Objekts vorstellen, das sich innerhalb der JavaScript-Engine befindet und vor dem von Ihnen geschriebenen Code verborgen ist. Die eckigen Klammern[[Prototype]]
sind absichtlich und stellen eine ECMAScript-Spezifikationskonvention dar, um interne Steckplätze zu kennzeichnen.Der Wert, auf den
[[Prototype]]
ein Objekt zeigt, wird umgangssprachlich als "Prototyp dieses Objekts" bezeichnet.Wenn Sie über die Notation dot (
obj.propName
) oder bracket (obj['propName']
) auf eine Eigenschaft zugreifen und das Objekt nicht direkt über eine solche Eigenschaft verfügt (dh über eine eigene Eigenschaft , die über überprüft werden kannobj.hasOwnProperty('propName')
), sucht die Laufzeit auf dem referenzierten Objekt nach einer Eigenschaft mit diesem Namen von der[[Prototype]]
stattdessen. Wenn der[[Prototype]]
auch keine solche Eigenschaft hat,[[Prototype]]
wird diese der Reihe nach überprüft und so weiter. Auf diese Weise wird die Prototypkette des Originalobjekts durchlaufen, bis eine Übereinstimmung gefunden oder das Ende erreicht ist. An der Spitze der Prototypenkette steht dernull
Wert.Moderne JavaScript-Implementierungen ermöglichen Lese- und / oder Schreibzugriff auf
[[Prototype]]
Folgendes:new
Operator (konfiguriert die Prototypkette für das Standardobjekt, das von einer Konstruktorfunktion zurückgegeben wird),extends
Schlüsselwort (konfiguriert die Prototypkette bei Verwendung der Klassensyntax),Object.create
setzt das angegebene Argument als das[[Prototype]]
des resultierenden Objekts,Object.getPrototypeOf
undObject.setPrototypeOf
([[Prototype]]
nach der Objekterstellung abrufen / setzen ) und__proto__
(ähnlich wie 4.)Object.getPrototypeOf
undObject.setPrototypeOf
werden teilweise deshalb bevorzugt__proto__
, weil das Verhalten vono.__proto__
ungewöhnlich ist, wenn ein Objekt einen Prototyp von hatnull
.Ein Objekt
[[Prototype]]
wird anfänglich während der Objekterstellung festgelegt.Wenn Sie ein neues Objekt über erstellen
new Func()
, wird das Objekt[[Prototype]]
standardmäßig auf das Objekt gesetzt, auf das verwiesen wirdFunc.prototype
.Beachten Sie daher, dass alle Klassen und alle Funktionen, die mit dem
new
Operator verwendet werden können,.prototype
zusätzlich zu ihrem eigenen[[Prototype]]
internen Steckplatz eine Eigenschaft benannt haben . Diese doppelte Verwendung des Wortes "Prototyp" ist die Quelle endloser Verwirrung unter Neulingen in der Sprache.Die Verwendung
new
mit Konstruktorfunktionen ermöglicht es uns, die klassische Vererbung in JavaScript zu simulieren. Obwohl das Vererbungssystem von JavaScript - wie wir gesehen haben - prototypisch und nicht klassenbasiert ist.Vor der Einführung der Klassensyntax in JavaScript waren Konstruktorfunktionen die einzige Möglichkeit, Klassen zu simulieren. Wir können uns Eigenschaften des Objekts vorstellen, auf das durch die Eigenschaft der Konstruktorfunktion verwiesen wird,
.prototype
als gemeinsam genutzte Elemente. dh. Mitglieder, die für jede Instanz gleich sind. In klassenbasierten Systemen werden Methoden für jede Instanz auf dieselbe Weise implementiert, sodass Methoden konzeptionell zur.prototype
Eigenschaft hinzugefügt werden . Die Felder eines Objekts sind jedoch instanzspezifisch und werden daher während der Erstellung dem Objekt selbst hinzugefügt.Ohne die Klassensyntax mussten Entwickler die Prototypenkette manuell konfigurieren, um eine ähnliche Funktionalität wie bei der klassischen Vererbung zu erzielen. Dies führte zu einem Übergewicht verschiedener Wege, um dies zu erreichen.
Hier ist eine Möglichkeit:
... und hier ist ein anderer Weg:
Die in ES2015 eingeführte Klassensyntax vereinfacht die Dinge, indem sie
extends
als " einzig wahre Möglichkeit" die Konfiguration der Prototypenkette bereitstellt , um die klassische Vererbung in JavaScript zu simulieren.Ähnlich wie im obigen Code, wenn Sie die Klassensyntax verwenden, um ein neues Objekt wie folgt zu erstellen:
... das resultierende Objekt
[[Prototype]]
wird auf eine Instanz von gesetztParent
, deren[[Prototype]]
wiederum istParent.prototype
.Wenn Sie schließlich ein neues Objekt über erstellen
Object.create(foo)
, werden die resultierenden Objekte auf[[Prototype]]
gesetztfoo
.quelle
In einer Sprache, die klassische Vererbung wie Java, C # oder C ++ implementiert, erstellen Sie zunächst eine Klasse - eine Blaupause für Ihre Objekte - und können dann neue Objekte aus dieser Klasse erstellen oder die Klasse erweitern und eine neue Klasse definieren, die erweitert wird die ursprüngliche Klasse.
In JavaScript erstellen Sie zuerst ein Objekt (es gibt kein Klassenkonzept), dann können Sie Ihr eigenes Objekt erweitern oder neue Objekte daraus erstellen. Es ist nicht schwierig, aber ein wenig fremd und schwer zu metabolisieren für jemanden, der an die klassische Art gewöhnt ist.
Beispiel:
Bis jetzt habe ich das Basisobjekt erweitert, jetzt erstelle ich ein anderes Objekt und erbe dann von Person.
Code-Snippet anzeigen
Wie gesagt, ich kann setAmountDue () nicht aufrufen, getAmountDue () für eine Person.
quelle
Customer.prototype = new Person();
Zeile zeigt MDN ein Beispiel mitCustomer.prototype = Object.create(Person.prototype)
und gibt an, dass 'Ein häufiger Fehler hier die Verwendung von "new Person ()" ist . QuelleDies ist ein sehr einfaches prototypbasiertes Objektmodell, das während der Erklärung als Beispiel betrachtet wird, ohne dass ein Kommentar vorliegt:
Es gibt einige entscheidende Punkte, die wir berücksichtigen müssen, bevor wir das Prototypkonzept durchgehen.
1- Wie JavaScript-Funktionen tatsächlich funktionieren:
Um den ersten Schritt zu machen, müssen wir herausfinden, wie JavaScript-Funktionen tatsächlich funktionieren, als klassenähnliche Funktion, die ein
this
Schlüsselwort verwendet, oder einfach als reguläre Funktion mit ihren Argumenten, was sie tut und was sie zurückgibt.Angenommen, wir möchten ein
Person
Objektmodell erstellen . Aber in diesem Schritt werde ich versuchen, genau das Gleiche zu tun, ohneprototype
und zu verwendennew
Stichwort .Also in diesem Schritt
functions
,objects
undthis
Stichwort, ist alles , was wir haben.Die erste Frage wäre, wie ein
this
Schlüsselwort ohne Verwendung einesnew
Schlüsselworts nützlich sein könnte .Um das zu beantworten, nehmen wir an, wir haben ein leeres Objekt und zwei Funktionen wie:
und jetzt ohne zu benutzen
new
Schlüsselwort, wie wir diese Funktionen verwenden könnten. JavaScript bietet dazu drei verschiedene Möglichkeiten:ein. Der erste Weg besteht darin, die Funktion als reguläre Funktion aufzurufen:
In diesem Fall ist dies das aktuelle Kontextobjekt, bei dem es sich normalerweise um das globale
window
Objekt im Browser oder handeltGLOBAL
in handeltNode.js
. Dies bedeutet, dass wir window.name im Browser oder GLOBAL.name in Node.js mit "George" als Wert haben würden.b. Wir können anhängen sie als ihre Eigenschaften an ein Objekt
- Der einfachste Weg , dies zu tun, besteht darin, das leere
person
Objekt zu ändern, wie:Auf diese Weise können wir sie wie folgt nennen:
und jetzt ist das
person
Objekt wie:- Die andere Möglichkeit, eine Eigenschaft an ein Objekt anzuhängen , besteht darin, das
prototype
Objekt zu verwenden, das in jedem JavaScript-Objekt mit dem Namen "zu finden"__proto__
ist. Ich habe versucht, es im Zusammenfassungsteil ein wenig zu erläutern. So könnten wir das gleiche Ergebnis erzielen, indem wir Folgendes tun:Auf diese Weise ändern wir jedoch das
Object.prototype
, denn wenn wir ein JavaScript-Objekt mit literals ({ ... }
) erstellen , wird es basierend auf erstelltObject.prototype
, was bedeutet, dass es als Attribut mit dem Namen an das neu erstellte Objekt angehängt wird.__proto__
Wenn wir es also ändern Wie bei unserem vorherigen Code-Snippet würden alle JavaScript-Objekte geändert, was keine gute Vorgehensweise ist. Was könnte jetzt die bessere Praxis sein:und jetzt sind andere Objekte in Frieden, aber es scheint immer noch keine gute Praxis zu sein. Wir haben also noch eine weitere Lösung, aber um diese Lösung zu verwenden, sollten wir zu der Codezeile zurückkehren, in der das
person
Objekt erstellt wurde (var person = {};
), und sie dann wie folgt ändern:Es wird ein neues JavaScript erstellt
Object
und daspropertiesObject
an das__proto__
Attribut angehängt. So stellen Sie sicher, dass Sie Folgendes tun können:Der schwierige Punkt hierbei ist jedoch, dass Sie Zugriff auf alle Eigenschaften haben, die
__proto__
auf der ersten Ebene desperson
Objekts definiert sind (lesen Sie den Zusammenfassungsteil für weitere Einzelheiten).Wie Sie sehen, würde die Verwendung einer dieser beiden Möglichkeiten
this
genau auf die zeigenperson
Objekt zeigen.c. JavaScript bietet eine andere Möglichkeit, die Funktion bereitzustellen
this
, nämlich Aufruf oder Anwenden , um die Funktion aufzurufen.und
Auf diese Weise, die mein Favorit ist, können wir unsere Funktionen leicht aufrufen wie:
oder
Diese drei Methoden sind die wichtigsten ersten Schritte, um die .prototype-Funktionalität herauszufinden.
2- Wie funktioniert das
new
Schlüsselwort?Dies ist der zweite Schritt, um die
.prototype
Funktionalität zu verstehen. Dies ist, was ich verwende, um den Prozess zu simulieren:In diesem Teil werde ich versuchen, alle Schritte auszuführen, die JavaScript unternimmt, ohne das
new
Schlüsselwort zu verwenden undprototype
wenn Sie dasnew
Schlüsselwort verwenden. Wenn wir dies tunnew Person("George")
,Person
dient die Funktion als Konstruktor. Dies ist, was JavaScript nacheinander tut:ein. Zunächst wird ein leeres Objekt erstellt, im Grunde genommen ein leerer Hash wie:
b. Der nächste Schritt, den JavaScript ausführt, besteht darin, alle Prototypobjekte an das neu erstellte Objekt anzuhängen
Wir haben
my_person_prototype
hier ähnlich wie das Prototypobjekt.Es ist nicht die Art und Weise, wie JavaScript die im Prototyp definierten Eigenschaften tatsächlich anfügt. Der tatsächliche Weg hängt mit dem Konzept der Prototypenkette zusammen.
ein. & b. Anstelle dieser beiden Schritte können Sie genau das gleiche Ergebnis erzielen, indem Sie Folgendes tun:
Jetzt können wir die
getName
Funktion in unserem aufrufenmy_person_prototype
:c. dann gibt es dieses Objekt dem Konstruktor,
Wir können dies mit unserer Probe tun wie:
oder
dann kann der Konstruktor tun, was er will, weil dies Innere dieses Konstruktors das Objekt ist, das gerade erstellt wurde.
Jetzt das Endergebnis, bevor die anderen Schritte simuliert werden: Objekt {Name: "George"}
Zusammenfassung:
Wenn Sie das neue Schlüsselwort für eine Funktion verwenden, rufen Sie dies grundsätzlich auf, und diese Funktion dient als Konstruktor. Wenn Sie also sagen:
JavaScript erstellt intern ein Objekt, einen leeren Hash, und gibt dieses Objekt dann an den Konstruktor weiter. Dann kann der Konstruktor tun, was er will, da dieses Innere dieses Konstruktors das gerade erstellte Objekt ist und Sie dann natürlich dieses Objekt erhalten wenn Sie die return-Anweisung in Ihrer Funktion nicht verwendet haben oder wenn Sie
return undefined;
am Ende Ihres Funktionskörpers eine setzen.Wenn JavaScript eine Eigenschaft für ein Objekt nachschlägt, sucht es zunächst nach diesem Objekt. Und dann gibt es eine geheime Eigenschaft,
[[prototype]]
wie wir sie normalerweise haben,__proto__
und diese Eigenschaft sieht JavaScript als nächstes an. Und wenn es durch das__proto__
, sofern es wieder ein anderes JavaScript-Objekt ist, ein eigenes__proto__
Attribut hat, geht es immer weiter, bis es den Punkt erreicht, an dem das nächste__proto__
null ist. Der Punkt ist das einzige Objekt in JavaScript , dass sein__proto__
Attribut null ist , istObject.prototype
Gegenstand:Und so funktioniert die Vererbung in JavaScript.
Mit anderen Worten, wenn Sie eine Prototyp-Eigenschaft für eine Funktion haben und eine neue aufrufen, wird nach dem Durchsuchen des neu erstellten Objekts durch JavaScript nach Eigenschaften die Funktion überprüft,
.prototype
und es ist auch möglich, dass dieses Objekt seine hat eigener interner Prototyp. und so weiter.quelle
__proto__
werden zuerst alle Prototyp-Eigenschaften der obersten Ebene gelöscht, und dann haben Sie eine neue Protobasis, die nur dann freigegeben wird, wenn Sie sie freigeben.Die sieben Koans des Prototyps
Als Ciro San nach tiefer Meditation den Mount Fire Fox hinabstieg, war sein Geist klar und friedlich.
Seine Hand war jedoch unruhig und ergriff von sich aus einen Pinsel und notierte die folgenden Notizen.
0) Zwei verschiedene Dinge können als "Prototyp" bezeichnet werden:
die Prototyp-Eigenschaft, wie in
obj.prototype
die interne Eigenschaft des Prototyps, bezeichnet wie
[[Prototype]]
in ES5 .Es kann über den ES5 abgerufen werden
Object.getPrototypeOf()
.Firefox macht es über die
__proto__
Eigenschaft als Erweiterung zugänglich . ES6 erwähnt nun einige optionale Anforderungen für__proto__
.1) Diese Konzepte existieren, um die Frage zu beantworten:
Intuitiv sollte die klassische Vererbung die Suche nach Eigenschaften beeinflussen.
2)
__proto__
wird für die.
Suche nach Punkteigenschaften wie in verwendetobj.property
..prototype
wird nicht direkt für die Suche verwendet, sondern nur indirekt, wie es__proto__
bei der Objekterstellung mit bestimmtnew
.Die Suchreihenfolge lautet:
obj
Eigenschaften hinzugefügt mitobj.p = ...
oderObject.defineProperty(obj, ...)
obj.__proto__
obj.__proto__.__proto__
und so weiter__proto__
istnull
, kehren Sie zurückundefined
.Dies ist die sogenannte Prototypenkette .
Sie können das
.
Nachschlagen mitobj.hasOwnProperty('key')
und vermeidenObject.getOwnPropertyNames(f)
3) Es gibt zwei Hauptmethoden zum Einstellen
obj.__proto__
:new
::dann
new
hat gesetzt:Hier wird
.prototype
verwendet.Object.create
::Sätze:
4) Der Code:
Entspricht dem folgenden Diagramm (einige
Number
Dinge werden weggelassen):Dieses Diagramm zeigt viele sprachdefinierte Objektknoten:
null
Object
Object.prototype
Function
Function.prototype
1
Number.prototype
(kann mit(1).__proto__
Klammern gefunden werden , die zur Erfüllung der Syntax obligatorisch sind)Unsere 2 Codezeilen haben nur die folgenden neuen Objekte erstellt:
f
F
F.prototype
i
ist jetzt eine Eigenschaft vonf
weil, wenn Sie tun:es wertet
F
mitthis
dem Wert ist, dernew
, kehrt die an wird dann zugewiesenf
.5)
.constructor
kommt normalerweise vonF.prototype
durch die.
Suche:Wenn wir schreiben
f.constructor
, sucht JavaScript wie folgt.
:f
hat nicht.constructor
f.__proto__ === F.prototype
hat.constructor === F
, also nimm esDas Ergebnis
f.constructor == F
ist intuitiv korrekt, daF
es zum Erstellen vonf
z. B. gesetzten Feldern verwendet wird, ähnlich wie in klassischen OOP-Sprachen.6) Klassische Vererbungssyntax kann durch Manipulieren von Prototypenketten erreicht werden.
ES6 fügt die Schlüsselwörter
class
und hinzuextends
, bei denen es sich hauptsächlich um Syntaxzucker für den zuvor möglichen Wahnsinn der Prototypmanipulation handelt.Vereinfachtes Diagramm ohne alle vordefinierten Objekte:
Nehmen wir uns einen Moment Zeit, um zu untersuchen, wie Folgendes funktioniert:
Die erste Zeile Sätze
c.i
zu1
wie in „4)“.In der zweiten Zeile, wenn wir:
.inc
wird durch die[[Prototype]]
Kette gefunden:c
->C
->C.prototype
->inc
X.Y()
, wird JavaScript innerhalb des Funktionsaufrufs automatischthis
auf gleich gesetzt !X
Y()
Die exakt gleiche Logik erklärt auch
d.inc
undd.inc2
.In diesem Artikel https://javascript.info/class#not-just-a-syntax-sugar werden weitere
class
wissenswerte Effekte erwähnt . Einige von ihnen sind möglicherweise nicht ohne dasclass
Schlüsselwort erreichbar (TODO check which):[[FunctionKind]]:"classConstructor"
, was den Konstruktor zwingt, mit new aufgerufen zu werden: Was ist der Grund, warum Konstruktoren der ES6-Klasse nicht als normale Funktionen aufgerufen werden können?Object.defineProperty
.use strict
. Kann mit einer explizitenuse strict
Funktion für jede Funktion durchgeführt werden, was zugegebenermaßen mühsam ist.quelle
.
Suche funktioniert (und wie viele Kopien der Daten erstellt werden). . Also machte ich mich daran, diesen Punkt zu verstehen. Der Rest sind Google + Blog-Beiträge + ein Js-Interpreter zur Hand. :)sets f.constructor = F
Teil war offensichtlich falsch und widersprach weiteren Abschnitten: Wird.constructor
durch.
Nachschlagen in der Prototypenkette gefunden. Es wurde jetzt behoben.f
der PrototypF
nur zur Bauzeit erstellt wird.f
wird es nicht wissen oder sich darum kümmernF.prototype
zu keinem Zeitpunkt nach dem ersten Bau etwas .prototype
ermöglicht es Ihnen, Klassen zu machen. wenn Sie nicht verwendenprototype
, wird es statisch.Hier ist ein kurzes Beispiel.
Im obigen Fall haben Sie einen statischen Funktionsaufruftest. Auf diese Funktion kann nur von obj.test zugegriffen werden, wo Sie sich vorstellen können, dass obj eine Klasse ist.
wo wie im folgenden Code
Das Objekt ist zu einer Klasse geworden, die jetzt instanziiert werden kann. Es können mehrere Instanzen von obj existieren, und alle haben die
test
Funktion haben.Das Obige ist mein Verständnis. Ich mache es zu einem Community-Wiki, damit die Leute mich korrigieren können, wenn ich falsch liege.
quelle
prototype
ist eine Eigenschaft von Konstruktorfunktionen, nicht von Instanzen, dh Ihr Code ist falsch! Vielleicht meinten Sie die nicht standardmäßige Eigenschaft__proto__
von Objekten, aber das ist ein ganz anderes Tier ...Nachdem ich diesen Thread gelesen habe, bin ich verwirrt mit der JavaScript-Prototypenkette. Dann habe ich diese Diagramme gefunden
http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance
Es ist ein übersichtliches Diagramm, das die JavaScript-Vererbung nach Prototypkette zeigt
und
http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/
Dieser enthält ein Beispiel mit Code und einige schöne Diagramme.
Ich hoffe, es ist auch hilfreich für Sie, die JavaScript-Prototypenkette zu verstehen.
quelle
[[Prototype]]
bedeutet?Jedes Objekt hat eine interne Eigenschaft, [[Prototype]] , die es mit einem anderen Objekt verknüpft:
In herkömmlichem Javascript ist das verknüpfte Objekt die
prototype
Eigenschaft einer Funktion:In einigen Umgebungen wird [[Prototype]] wie folgt verfügbar gemacht
__proto__
:Sie erstellen den Link [[Prototyp]] , wenn Sie ein Objekt erstellen.
Diese Aussagen sind also äquivalent:
Sie können das Linkziel nicht sehen (
Object.prototype
) in einer neuen Anweisung nicht sehen. Stattdessen wird das Ziel vom Konstruktor impliziert (Object
) .Merken:
prototype
Eigenschaft, die zunächst ein leeres Objekt enthält.prototype
Eigenschaft ihres Konstruktors verknüpft .prototype
Eigenschaft nicht verwendet.new
.quelle
Object.create()
docs , @sam. Links zu__proto__
undObject.prototype
wären nette Verbesserungen. Und ich mochte Ihre Beispiele, wie Prototypen mit Konstruktoren arbeiten undObject.create()
, aber sie waren wahrscheinlich der lange und weniger relevante Teil, den Sie loswerden wollten.Javascript hat keine Vererbung im üblichen Sinne, aber es hat die Prototypenkette.
Prototypkette
Wenn ein Mitglied eines Objekts im Objekt nicht gefunden werden kann, sucht es in der Prototypenkette danach. Die Kette besteht aus anderen Objekten. Auf den Prototyp einer bestimmten Instanz kann mit dem zugegriffen werden
__proto__
Variablen werden. Jedes Objekt hat eines, da es in Javascript keinen Unterschied zwischen Klassen und Instanzen gibt.Der Vorteil des Hinzufügens einer Funktion / Variablen zum Prototyp besteht darin, dass sie nicht nur für jede Instanz, sondern nur einmal im Speicher gespeichert werden muss.
Es ist auch nützlich für die Vererbung, da die Prototypkette aus vielen anderen Objekten bestehen kann.
quelle
Dieser Artikel ist lang. Aber ich bin sicher, es wird die meisten Ihrer Fragen bezüglich der "prototypischen" Natur der JavaScript-Vererbung klären. Und noch mehr. Bitte lesen Sie den vollständigen Artikel.
JavaScript hat grundsätzlich zwei Arten von Datentypen
Nicht Objekte
Im Folgenden sind die Nicht-Objekt -Datentypen aufgeführt
Diese Datentypen werden wie folgt zurückgegeben, wenn Sie den Operator typeof verwenden
typeof "string literal" (oder eine Variable, die string literal enthält) === 'string'
typeof 5 (oder ein beliebiges numerisches Literal oder eine Variable, die ein numerisches Literal oder NaN oder Infynity enthält ) === 'number'
typeof true (oder false oder eine Variable, die true oder false enthält ) === 'boolean'
typeof undefined (oder eine undefinierte Variable oder eine Variable, die undefined enthält ) === 'undefined'
Die Datentypen string , number und boolean können sowohl als Objekte als auch als Nicht-Objekte dargestellt werden. Wenn sie als Objekte dargestellt werden, ist ihr Typ immer === 'Objekt'. Wir werden darauf zurückkommen, sobald wir die Objektdatentypen verstanden haben.
Objekte
Die Objektdatentypen können weiter in zwei Typen unterteilt werden
Die Objekte vom Typ Funktion geben die Zeichenfolge 'function' mit dem Operator typeof zurück . Alle benutzerdefinierten Funktionen und alle in JavaScript integrierten Objekte, die mithilfe eines neuen Operators neue Objekte erstellen können, fallen in diese Kategorie. Zum Beispiel.
Also, typeof (Object) === typeof (String) === typeof (Number) === typeof (Boolean) === typeof (Array) === typeof (RegExp) === typeof (Function) == = typeof (UserDefinedFunction) === 'function'
Alle Objekte vom Typ Funktion sind tatsächlich Instanzen der integrierten JavaScript- Objektfunktion (einschließlich des Funktionsobjekts , dh es ist rekursiv definiert). Es ist, als ob diese Objekte folgendermaßen definiert worden wären
Wie bereits erwähnt, können die Objekte vom Funktionstyp mit dem neuen Operator weitere Objekte erstellen . Beispielsweise kann ein Objekt vom Typ Object , String , Number , Boolean , Array , RegExp oder UserDefinedFunction mithilfe von erstellt werden
Die Objekte so erstellt sind alle Typ Non Funktionsobjekte und zurück ihre typeof === ‚Objekt‘ . In all diesen Fällen kann das Objekt "a" mit dem Operator new keine Objekte mehr erstellen. Das Folgende ist also falsch
Das eingebaute Objekt Math ist typeof === 'object' . Daher kann ein neues Objekt vom Typ Math nicht durch einen neuen Operator erstellt werden.
Beachten Sie auch, dass Objekt- , Array- und RegExp- Funktionen ein neues Objekt erstellen können, ohne den Operator new zu verwenden . Die folgenden tun dies jedoch nicht.
Die benutzerdefinierten Funktionen sind Sonderfälle.
Da Objekte vom Typ Funktion neue Objekte erstellen können, werden sie auch als Konstruktoren bezeichnet .
Jeder Konstruktor / jede Funktion (ob eingebaut oder benutzerdefiniert) hat automatisch eine Eigenschaft namens "Prototyp", deren Wert standardmäßig als Objekt festgelegt ist. Dieses Objekt selbst hat eine Eigenschaft namens "Konstruktor", die standardmäßig auf den Konstruktor / die Funktion verweist .
Zum Beispiel, wenn wir eine Funktion definieren
Folgendes geschieht automatisch
Diese "Prototyp" -Eigenschaft ist nur in Objekten vom Typ "Funktion" (und niemals in Objekten vom Typ "Nicht-Funktion" ) vorhanden.
Dies liegt daran, dass beim Erstellen eines neuen Objekts (unter Verwendung eines neuen Operators) alle Eigenschaften und Methoden vom aktuellen Prototypobjekt der Konstruktorfunktion geerbt werden, dh im neu erstellten Objekt wird eine interne Referenz erstellt, die auf das Objekt verweist, auf das das aktuelle Prototypobjekt der Konstruktorfunktion verweist.
Diese "interne Referenz" , die im Objekt zum Verweisen auf geerbte Eigenschaften erstellt wird, wird als Prototyp des Objekts bezeichnet (der auf das Objekt verweist, auf das durch die Eigenschaft "Prototyp" des Konstruktors verwiesen wird, sich jedoch von diesem unterscheidet). Für jedes Objekt (Funktion oder Nichtfunktion) kann dies mit der Object.getPrototypeOf () -Methode abgerufen werden . Mit dieser Methode kann man die Prototypkette eines Objekts verfolgen.
Außerdem verfügt jedes erstellte Objekt ( Funktionstyp oder Nichtfunktionstyp ) über eine "Konstruktor" -Eigenschaft, die von dem Objekt geerbt wird, auf das durch die Prototyp-Eigenschaft der Konstruktorfunktion verwiesen wird. Standardmäßig verweist diese "Konstruktor" -Eigenschaft auf die Konstruktorfunktion , die sie erstellt hat (wenn der Standard- "Prototyp" der Konstruktorfunktion nicht geändert wird).
Für alle Objekte vom Typ Funktion ist die Konstruktorfunktion immer function Function () {}
Bei Objekten vom Typ Nichtfunktion (z. B. in Math erstelltes Javascript-Objekt) ist die Konstruktorfunktion die Funktion, die sie erstellt hat. Für das Math- Objekt ist es die Funktion Object () {} .
Alle oben erläuterten Konzepte können ohne unterstützenden Code ein wenig entmutigend zu verstehen sein. Bitte gehen Sie den folgenden Code Zeile für Zeile durch, um das Konzept zu verstehen. Versuchen Sie es auszuführen, um ein besseres Verständnis zu haben.
Die Prototypenkette jedes Objekts geht letztendlich auf Object.prototype zurück (das selbst kein Prototypobjekt hat). Der folgende Code kann zum Verfolgen der Prototypkette eines Objekts verwendet werden
Die Prototypenkette für verschiedene Objekte funktioniert wie folgt.
Verwenden Sie zum Erstellen eines Objekts ohne Prototyp Folgendes:
Man könnte denken, dass das Setzen der Prototyp-Eigenschaft des Konstruktors auf Null ein Objekt mit einem Null-Prototyp erzeugen soll. In solchen Fällen wird der Prototyp des neu erstellten Objekts jedoch auf Object.prototype und sein Konstruktor auf die Funktion Object gesetzt. Dies wird durch den folgenden Code demonstriert
Folgen Sie in der Zusammenfassung dieses Artikels
Nur Objekte vom Typ Funktion können mit dem Operator new ein neues Objekt erstellen . Die so erstellten Objekte sind Objekte vom Typ Nichtfunktion. Die Objekte vom Typ Non Function können mit dem Operator new kein Objekt mehr erstellen .
Alle Objekte vom Typ Funktion haben standardmäßig die Eigenschaft "Prototyp" . Diese "Prototyp" -Eigenschaft verweist auf ein Objekt mit einer "Konstruktor" -Eigenschaft, die standardmäßig auf das Objekt vom Funktionstyp selbst verweist .
Alle Objekte ( Funktionstyp und Nichtfunktionstyp ) haben eine "Konstruktor" -Eigenschaft, die standardmäßig auf den Funktionstyp Objekt / verweist Konstruktor sie erstellt wurden.
Jedes Objekt, das intern erstellt wird, verweist auf das Objekt, auf das durch die Eigenschaft "prototype" des Konstruktors verwiesen wird , der es erstellt hat. Dieses Objekt wird als Prototyp des erstellten Objekts bezeichnet (unterscheidet sich von der Eigenschaft "Prototyp" von Funktionstypobjekten, auf die es verweist). Auf diese Weise kann das erstellte Objekt direkt auf die Methoden und Eigenschaften zugreifen, die in dem Objekt definiert sind, auf das die Eigenschaft "Prototyp" des Konstruktors verweist (zum Zeitpunkt der Objekterstellung).
Der Prototyp eines Objekts (und damit seine geerbten Eigenschaftsnamen) kann mit der Object.getPrototypeOf () -Methode abgerufen werden . Tatsächlich kann diese Methode zum Navigieren in der gesamten Prototypenkette des Objekts verwendet werden.
Die Prototypkette jedes Objekts geht letztendlich auf Object.prototype zurück (es sei denn, das Objekt wird mit Object.create (null) erstellt. In diesem Fall hat das Objekt keinen Prototyp).
typeof (new Array ()) === 'object' ist ein Sprachentwurf und kein Fehler, wie von Douglas Crockford angegeben
Wenn Sie die Prototyp-Eigenschaft des Konstruktors auf null (oder undefiniert, number, true, false, string) setzen, wird kein Objekt mit einem Null-Prototyp erstellt. In solchen Fällen wird der Prototyp des neu erstellten Objekts auf Object.prototype und der Konstruktor auf die Funktion Object gesetzt.
Hoffe das hilft.
quelle
Das Konzept der
prototypal
Vererbung ist für viele Entwickler eines der kompliziertesten. Versuchen wir, die Wurzel des Problems zu verstehen, um esprototypal inheritance
besser zu verstehen . Beginnen wir mit einerplain
Funktion.Wenn wir einen
new
Operator auf dem verwendenTree function
, rufen wir ihn alsconstructor
Funktion auf.Jede
JavaScript
Funktion hat eineprototype
. Wenn Sie das protokollierenTree.prototype
, erhalten Sie ...Wenn Sie sich die obige
console.log()
Ausgabe ansehen , sehen Sie möglicherweise eine KonstruktoreigenschaftTree.prototype
und auch eine__proto__
Eigenschaft. Das__proto__
stellt das darprototype
, worauf diesfunction
basiert, und da dies nur eine Ebene ist , die nochJavaScript function
nichtinheritance
eingerichtet ist, bezieht es sich auf dasObject prototype
, was gerade in JavaScript eingebaut wurde ...https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
Das hat Dinge wie
.toString, .toValue, .hasOwnProperty
etc ...__proto__
was gebracht wurde meine Mozilla ist veraltet und wird durchObject.getPrototypeOf
Methode ersetzt, um die zu bekommenobject's prototype
.Fügen wir unserer Methode eine Methode hinzu
Tree
prototype
.Wir haben das geändert
Root
und einenfunction
Zweig hinzugefügt .Das heißt, wenn Sie ein
instance
von erstellenTree
, können Sie dessenbranch
Methode aufrufen .Wir können auch hinzufügen
primitives
oderobjects
zu unseremPrototype
.Fügen wir ein
child-tree
zu unserem hinzuTree
.Hier
Child
erbt dasprototype
von Tree. Wir verwenden hier eineObject.create()
Methode, um ein neues Objekt zu erstellen, das auf dem basiert, was Sie übergeben. Hier ist esTree.prototype
. In diesem Fall setzen wir den Prototyp von Child auf ein neues Objekt, das mit demTree
Prototyp identisch aussieht . Als nächstes setzen wir dasChild's constructor to Child
, wenn wir es nicht tun, würde es darauf hinweisenTree()
.Child
Jetzt hat es seine eigenenprototype
, seine__proto__
Punkte aufTree
undTree's prototype
Punkte auf BasisObject
.Jetzt erstellen Sie ein
instance
vonChild
und rufen auf,branch
das ursprünglich in verfügbar warTree
. Wir haben unserebranch
auf der nicht wirklich definiertChild prototype
. ABER, in demRoot prototype
das Kind erbt.In JS ist alles kein Objekt, alles kann sich wie ein Objekt verhalten.
Javascript
hat Primitive wiestrings, number, booleans, undefined, null.
Sie sind nichtobject(i.e reference types)
, können aber sicherlich wie ein handelnobject
. Schauen wir uns hier ein Beispiel an.In der ersten Zeile dieser Liste
primitive
wird dem Namen ein Zeichenfolgenwert zugewiesen. In der zweiten Zeile wird der Name wie ein behandeltobject
undcharAt(0)
mit der Punktnotation aufgerufen.Dies passiert hinter den Kulissen: // was die
JavaScript
Engine tutDas
String object
existiert nur für eine Anweisung, bevor es zerstört wird (ein Prozess, der aufgerufen wirdautoboxing
). Kommen wir noch einmal zu unserem zurückprototypal
inheritance
.Javascript
unterstützt die Vererbung überdelegation
basierend aufprototypes
.Function
hat eineprototype
Eigenschaft, die auf ein anderes Objekt verweist.properties/functions
werden vonobject
sich aus oder überprototype
Kette gesucht , wenn es nicht existiertA
prototype
in JS ist ein Objekt, dasyields
Sie dem Elternteil eines anderen übermittelnobject
. [dh Delegation]Delegation
bedeutet, dass Sie, wenn Sie nicht in der Lage sind, etwas zu tun, jemand anderem sagen, dass er es für Sie tun soll.https://jsfiddle.net/say0tzpL/1/
Wenn Sie die obige Geige nachschlagen, hat der Hund Zugriff auf die
toString
Methode, die jedoch nicht darin verfügbar ist, sondern über die Prototypenkette, an die delegiert wirdObject.prototype
Wenn Sie sich das folgende ansehen, versuchen wir, auf die
call
Methode zuzugreifen , die in jedem verfügbar istfunction
.https://jsfiddle.net/rknffckc/
Wenn Sie die obige Geige nachschlagen, hat
Profile
Function Zugriff auf diecall
Methode, diese ist jedoch nicht verfügbar, sondern über die Prototypenkette, an die delegiert wirdFunction.prototype
Hinweis:
prototype
ist eine Eigenschaft des Funktionskonstruktors, während__proto__
eine Eigenschaft der aus dem Funktionskonstruktor erstellten Objekte ist. Jede Funktion enthält eineprototype
Eigenschaft, deren Wert leer istobject
. Wenn wir eine Instanz der Funktion erstellen, erhalten wir eine interne Eigenschaft[[Prototype]]
oder__proto__
deren Referenz der Prototyp der Funktion istconstructor
.Das obige Diagramm sieht etwas kompliziert aus, zeigt aber das ganze Bild, wie
prototype chaining
funktioniert. Lassen Sie uns dies langsam durchgehen:Es gibt zwei Instanzen
b1
undb2
, deren KonstruktorBar
und übergeordnetes Element Foo ist und zwei Methoden aus der Prototypenketteidentify
undspeak
viaBar
und hatFoo
https://jsfiddle.net/kbp7jr7n/
Wenn Sie den obigen Code nachschlagen, haben wir einen
Foo
Konstruktor mit der Methodeidentify()
und einenBar
Konstruktor mit derspeak
Methode. Wir schaffen zweiBar
Instanzenb1
undb2
dessen Muttertypen istFoo
. Während wir diespeak
Methode von aufrufenBar
, können wir nun identifizieren, wer über dieprototype
Kette das Sprechen aufruft .Bar
hat jetzt alle Methoden, vonFoo
denen in seiner definiert sindprototype
. Lassen Sie uns weiter gehen, um dasObject.prototype
undFunction.prototype
und ihre Beziehung zu verstehen . Wenn Sie den Konstruktor nachschlagenFoo
,Bar
undObject
sindFunction constructor
.Das
prototype
vonBar
istFoo
,prototype
vonFoo
istObject
und wenn Sie genau hinschauen, ist dasprototype
vonFoo
verwandt mitObject.prototype
.Bevor wir dies schließen, lassen Sie uns hier nur einen kleinen Code einschließen, um alles oben zusammenzufassen . Wir verwenden
instanceof
hier den Operator, um zu überprüfen, ob einobject
in seinerprototype
Kette dieprototype
Eigenschaft eines hat,constructor
die das gesamte große Diagramm zusammenfasst.Ich hoffe, dass dieses Add einige Informationen enthält. Ich weiß, dass dies ein bisschen zu verstehen sein könnte. In einfachen Worten, es sind nur Objekte, die mit Objekten verbunden sind.
quelle
Die Schnittstelle zu Standardklassen wird erweiterbar. Beispielsweise verwenden Sie die
Array
Klasse und müssen außerdem einen benutzerdefinierten Serializer für alle Ihre Array-Objekte hinzufügen. Würden Sie Zeit damit verbringen, eine Unterklasse zu codieren oder Komposition oder ... zu verwenden? Die Prototyp-Eigenschaft löst dieses Problem, indem die Benutzer die genaue Gruppe von Mitgliedern / Methoden steuern können, die einer Klasse zur Verfügung stehen.Stellen Sie sich Prototypen als zusätzlichen vtable-Zeiger vor. Wenn einige Mitglieder in der ursprünglichen Klasse fehlen, wird der Prototyp zur Laufzeit nachgeschlagen.
quelle
Es kann hilfreich sein, Prototypketten in zwei Kategorien einzuteilen.
Betrachten Sie den Konstruktor:
Der Wert von
Object.getPrototypeOf(Person)
ist eine Funktion. In der Tat ist esFunction.prototype
. DaPerson
es als Funktion erstellt wurde, verwendet es dasselbe Prototyp-Funktionsobjekt wie alle Funktionen. Es ist dasselbe wiePerson.__proto__
, aber diese Eigenschaft sollte nicht verwendet werden. Wie auch immer, mitObject.getPrototypeOf(Person)
Ihnen steigen Sie effektiv die Leiter der sogenannten Prototypenkette hinauf.Die Kette nach oben sieht folgendermaßen aus:
Person
→Function.prototype
→Object.prototype
(Endpunkt)Wichtig ist, dass diese Prototypenkette wenig mit den Objekten zu tun hat,
Person
die konstruiert werden können . Diese konstruierten Objekte haben eine eigene Prototypkette, und diese Kette kann möglicherweise keinen engen Vorfahren gemeinsam mit dem oben genannten haben.Nehmen Sie zum Beispiel dieses Objekt:
p hat keine direkte Beziehung zwischen Prototyp und Kette zur Person . Ihre Beziehung ist eine andere. Das Objekt p hat eine eigene Prototypkette. Wenn
Object.getPrototypeOf
Sie verwenden, finden Sie die Kette wie folgt:p
→Person.prototype
→Object.prototype
(Endpunkt)Es gibt kein Funktionsobjekt in dieser Kette (obwohl das sein könnte).
Es
Person
scheint also mit zwei Arten von Ketten verwandt zu sein, die ihr eigenes Leben führen. Um von einer Kette zur anderen zu "springen", verwenden Sie:.prototype
: Springe von der Konstruktorkette zur Kette des erstellten Objekts. Diese Eigenschaft ist daher nur für Funktionsobjekte definiert (wienew
sie nur für Funktionen verwendet werden können)..constructor
: Springe von der Kette des erstellten Objekts zur Kette des Konstruktors.Hier ist eine visuelle Darstellung der beiden beteiligten Prototypketten, dargestellt als Spalten:
Zusammenfassen:
Es ist keine Überraschung, dass der Name der Immobilie
prototype
zu Verwirrung führen kann. Es wäre vielleicht klarer gewesen, wenn diese Eigenschaft benannt worden wäreprototypeOfConstructedInstances
oder etwas in dieser Richtung.Sie können zwischen den beiden Prototypenketten hin und her springen:
Diese Symmetrie kann durch explizites Zuweisen eines anderen Objekts zur
prototype
Eigenschaft aufgehoben werden (dazu später mehr).Erstellen Sie eine Funktion, erhalten Sie zwei Objekte
Person.prototype
ist ein Objekt, das zur gleichen Zeit erstellt wurde, als die FunktionPerson
erstellt wurde. Es hatPerson
als Konstruktor, obwohl dieser Konstruktor noch nicht ausgeführt wurde. Es werden also zwei Objekte gleichzeitig erstellt:Person
selbstBeide sind Objekte, haben jedoch unterschiedliche Rollen: Das Funktionsobjekt wird konstruiert , während das andere Objekt den Prototyp eines Objekts darstellt, das von dieser Funktion erstellt wird. Das Prototypobjekt wird zum übergeordneten Objekt des konstruierten Objekts in seiner Prototypenkette.
Da eine Funktion auch ein Objekt ist, hat sie auch ein eigenes übergeordnetes Element in ihrer eigenen Prototypkette. Denken Sie jedoch daran, dass es bei diesen beiden Ketten um unterschiedliche Dinge geht.
Hier sind einige Gleichungen, die helfen könnten, das Problem zu verstehen - all diese Drucke
true
:Hinzufügen von Ebenen zur Prototypenkette
Obwohl beim Erstellen einer Konstruktorfunktion ein Prototypobjekt erstellt wird, können Sie dieses Objekt ignorieren und ein anderes Objekt zuweisen, das als Prototyp für alle nachfolgenden Instanzen verwendet werden soll, die von diesem Konstruktor erstellt wurden.
Zum Beispiel:
Jetzt ist die Prototypkette von t einen Schritt länger als die von p :
t
→p
→Person.prototype
→Object.prototype
(Endpunkt)Die andere Prototypenkette ist nicht länger:
Thief
undPerson
sind Geschwister, die denselben Elternteil in ihrer Prototypenkette teilen:Person
}Thief
} →Function.prototype
→Object.prototype
(Endpunkt)Die zuvor präsentierte Grafik kann dann darauf erweitert werden (das Original
Thief.prototype
wird weggelassen):Die blauen Linien repräsentieren Prototypketten, die anderen farbigen Linien repräsentieren andere Beziehungen:
quelle
Der endgültige Leitfaden für objektorientiertes JavaScript - eine sehr präzise und klare ~ 30-minütige Video-Erklärung der gestellten Frage (Thema Prototypal Inheritance beginnt um 5:45 Uhr , obwohl ich mir lieber das gesamte Video anhören möchte). Der Autor dieses Videos hat auch die JavaScript Object Visualizer-Website http://www.objectplayground.com/ erstellt .
quelle
Ich fand es hilfreich, die "Prototypenkette" als rekursive Konvention zu erklären, wenn
obj_n.prop_X
darauf verwiesen wird:Wenn
obj_n.prop_X
nicht vorhanden, überprüfen Sie,obj_n+1.prop_X
woobj_n+1 = obj_n.[[prototype]]
Wenn das
prop_X
schließlich im k-ten Prototypobjekt gefunden wird, dannobj_1.prop_X = obj_1.[[prototype]].[[prototype]]..(k-times)..[[prototype]].prop_X
Ein Diagramm der Beziehung von Javascript-Objekten anhand ihrer Eigenschaften finden Sie hier:
http://jsobjects.org
quelle
Wenn ein Konstruktor ein Objekt erstellt, verweist dieses Objekt implizit auf die Eigenschaft "Prototyp" des Konstruktors, um Eigenschaftsreferenzen aufzulösen. Auf die Eigenschaft "Prototyp" des Konstruktors kann durch den Programmausdruck constructor.prototype verwiesen werden, und Eigenschaften, die dem Prototyp eines Objekts hinzugefügt wurden, werden durch Vererbung von allen Objekten gemeinsam genutzt, die den Prototyp gemeinsam nutzen.
quelle
Hier gibt es zwei verschiedene, aber verwandte Einheiten, die erklärt werden müssen:
.prototype
Eigenschaft von Funktionen.[[Prototype]]
[1] -Eigenschaft aller Objekte [2] .Dies sind zwei verschiedene Dinge.
Die
[[Prototype]]
Eigenschaft:Dies ist eine Eigenschaft, die für alle [2] Objekte vorhanden ist.
Was hier gespeichert ist, ist ein anderes Objekt, das als Objekt selbst ein
[[Prototype]]
eigenes hat, das auf ein anderes Objekt zeigt. Das andere Objekt hat ein[[Prototype]]
eigenes. Diese Geschichte wird fortgesetzt, bis Sie das prototypische Objekt erreichen, das Methoden bereitstellt, auf die für alle Objekte (wie.toString
) zugegriffen werden kann .Die
[[Prototype]]
Eigenschaft ist Teil dessen, was die[[Prototype]]
Kette bildet . Diese Kette von[[Prototype]]
Objekten ist , was untersucht wird , wenn zum Beispiel[[Get]]
oder[[Set]]
Operationen an einem Objekt ausgeführt werden:Die
.prototype
Eigenschaft:Dies ist eine Eigenschaft, die nur für Funktionen vorhanden ist. Mit einer sehr einfachen Funktion:
Die
.prototype
Eigenschaft enthält ein Objekt , das Ihnen zugewiesen wird,b.[[Prototype]]
wenn Sie dies tunvar b = new Bar
. Sie können dies leicht untersuchen:Eines der wichtigsten
.prototype
ist das derObject
Funktion . Dieser Prototyp enthält das prototypische Objekt, das alle[[Prototype]]
Ketten enthalten. Darauf werden alle verfügbaren Methoden für neue Objekte definiert:Da
.prototype
es sich nun um ein Objekt handelt, hat es eine[[Prototype]]
Eigenschaft. Wenn Sie machen keine Zuweisungen anFunction.prototype
, die.prototype
‚s[[Prototype]]
verweist auf die prototypische Objekt (Object.prototype
). Dies wird automatisch durchgeführt, wenn Sie eine neue Funktion erstellen.Auf diese Weise erhalten Sie jedes Mal, wenn Sie
new Bar;
die Prototypenkette für Sie einrichten, alles definiertBar.prototype
und alles definiert aufObject.prototype
:Wenn Sie tun make Zuweisungen
Function.prototype
alles , was Sie tun , ist die Prototypkette erstreckt , ein weiteres Objekt umfassen. Es ist wie eine Einfügung in eine einfach verknüpfte Liste.Dies ändert im Wesentlichen die
[[Prototype]]
Kette, sodass Eigenschaften, die für das zugewiesene Objekt definiertFunction.prototype
sind, von jedem von der Funktion erstellten Objekt gesehen werden können.[1: Das wird niemanden verwirren; in vielen Implementierungen über die
__proto__
Eigenschaft verfügbar gemacht .[2]: Alle außer
null
.quelle
Lassen Sie mich Ihnen mein Verständnis von Prototypen erklären. Ich werde das Erbe hier nicht mit anderen Sprachen vergleichen. Ich wünschte, die Leute würden aufhören, Sprachen zu vergleichen, und die Sprache einfach als sich selbst verstehen. Das Verständnis von Prototypen und prototypischer Vererbung ist so einfach, wie ich Ihnen weiter unten zeigen werde.
Der Prototyp ist wie ein Modell, auf dessen Grundlage Sie ein Produkt erstellen. Der entscheidende Punkt, den Sie verstehen müssen, ist, dass die Verbindung zwischen dem Prototyp und dem Produkt dauerhaft ist, wenn Sie ein Objekt mit einem anderen Objekt als Prototyp erstellen. Zum Beispiel:
Jedes Objekt enthält eine interne Eigenschaft namens [[Prototyp]], auf die die
Object.getPrototypeOf()
Funktion zugreifen kann.Object.create(model)
erstellt ein neues Objekt und setzt es der [[Prototyp]] Eigenschaft für das Objekt - Modell . Daher , wenn Sie das tunObject.getPrototypeOf(product)
, werden Sie das Objekt erhalten Modell .Die Eigenschaften des Produkts werden folgendermaßen behandelt:
Eine solche Verknüpfung von Objekten mithilfe der Prototyp-Eigenschaft wird als prototypische Vererbung bezeichnet. Da ist es so einfach, stimme zu?
quelle
Ein weiterer Versuch, die auf JavaScript-Prototypen basierende Vererbung mit besseren Bildern zu erklären
quelle
Betrachten Sie das folgende
keyValueStore
Objekt:Ich kann eine neue Instanz dieses Objekts erstellen, indem ich Folgendes tue:
Jede Instanz dieses Objekts hätte die folgenden öffentlichen Eigenschaften:
data
get
set
delete
getLength
Angenommen, wir erstellen 100 Instanzen dieses
keyValueStore
Objekts. Auch wennget
,set
,delete
,getLength
wird für jede dieser 100 Fälle genau die gleiche Sache zu tun hat jede Instanz eine eigene Kopie dieser Funktion.Nun stellen Sie, wenn Sie nur einen einzigen haben könnten
get
,set
,delete
und zugetLength
kopieren, und jede Instanz würde die gleiche Funktion verweisen. Dies wäre besser für die Leistung und würde weniger Speicher benötigen.Hier kommen Prototypen ins Spiel. Ein Prototyp ist eine "Blaupause" von Eigenschaften, die geerbt, aber nicht von Instanzen kopiert werden. Dies bedeutet, dass es für alle Instanzen eines Objekts nur einmal im Speicher vorhanden ist und von allen diesen Instanzen gemeinsam genutzt wird.
Betrachten Sie nun das
keyValueStore
Objekt erneut. Ich könnte es so umschreiben:Dies entspricht genau der vorherigen Version des
keyValueStore
Objekts, außer dass alle seine Methoden jetzt in einem Prototyp gespeichert sind. Dies bedeutet, dass alle 100 Instanzen jetzt diese vier Methoden gemeinsam nutzen, anstatt jeweils eine eigene Kopie zu haben.quelle
Zusammenfassung:
new
Schlüsselwort verwendet wird, erhält das Objekt einen Prototyp. Ein Verweis auf diesen Prototyp befindet sich in der__proto__
Eigenschaft des neu erstellten Objekts.__proto__
Eigenschaft bezieht sich auf dieprototype
Eigenschaft der Konstruktorfunktion.Beispiel:
Warum ist das nützlich:
Javascript verfügt über einen Mechanismus zum Nachschlagen von Eigenschaften für Objekte, der als "prototypische Vererbung" bezeichnet wird.
Zum Beispiel:
Aktualisieren:
Die
__proto__
Eigenschaft ist veraltet, obwohl sie in den meisten modernen Browsern implementiert ist. Ein besserer Weg, um die Prototyp-Objektreferenz zu erhalten, wäre:Object.getPrototypeOf()
quelle
Ich mag immer Analogien, wenn es darum geht, solche Dinge zu verstehen. "Prototypische Vererbung" ist meiner Meinung nach im Vergleich zur Klassenbass-Vererbung ziemlich verwirrend, obwohl Prototypen ein viel einfacheres Paradigma sind. Tatsächlich gibt es bei Prototypen wirklich keine Vererbung, daher ist der Name an und für sich irreführend, es ist eher eine Art "Delegation".
Stell dir das vor ....
Du bist in der High School und du bist in der Klasse und hast ein Quiz, das heute fällig ist, aber du hast keinen Stift, um deine Antworten auszufüllen. Doh!
Sie sitzen neben Ihrem Freund Finnius, der vielleicht einen Stift hat. Sie fragen, und er sieht sich erfolglos an seinem Schreibtisch um, aber anstatt zu sagen "Ich habe keinen Stift", ist er ein netter Freund, den er mit seinem anderen Freund Derp überprüft, ob er einen Stift hat. Derp hat in der Tat einen Ersatzstift und gibt ihn an Finnius zurück, der ihn an Sie weitergibt, um Ihr Quiz abzuschließen. Derp hat den Stift Finnius anvertraut, der den Stift zur Verwendung an Sie delegiert hat.
Wichtig ist hier, dass Derp Ihnen den Stift nicht gibt, da Sie keine direkte Beziehung zu ihm haben.
Dies ist ein vereinfachtes Beispiel für die Funktionsweise von Prototypen, bei dem ein Datenbaum nach dem gesuchten Objekt durchsucht wird.
quelle
ein weiteres Schema, das __proto__- , Prototyp- und Konstruktorbeziehungen zeigt :
quelle
Es ist nur so, dass Sie bereits ein Objekt mit haben,
Object.new
aber Sie haben immer noch kein Objekt, wenn Sie die Konstruktorsyntax verwenden.quelle
Referenz: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes
quelle
Der Prototyp erstellt ein neues Objekt, indem er ein vorhandenes Objekt klont . Wenn wir also wirklich an Prototypen denken, können wir wirklich daran denken, etwas zu klonen oder zu kopieren, anstatt es zu erfinden.
quelle