Dies ist ein sehr einfaches prototypbasiertes Objektmodell, das während der Erklärung als Beispiel betrachtet wird, ohne dass ein Kommentar vorliegt:
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
console.log(this.name);
}
var person = new Person("George");
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, ohne prototype
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 eines new
Schlüsselworts nützlich sein könnte .
Um das zu beantworten, nehmen wir an, wir haben ein leeres Objekt und zwei Funktionen wie:
var person = {};
function Person(name){ this.name = name; }
function getName(){
console.log(this.name);
}
und jetzt ohne zu benutzennew
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:
Person("George");
getName();//would print the "George" in the console
In diesem Fall ist dies das aktuelle Kontextobjekt, bei dem es sich normalerweise um das globale window
Objekt im Browser oder handeltGLOBAL
in handelt Node.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:
person.Person = Person;
person.getName = getName;
Auf diese Weise können wir sie wie folgt nennen:
person.Person("George");
person.getName();// -->"George"
und jetzt ist das person
Objekt wie:
Object {Person: function, getName: function, name: "George"}
- 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:
person.__proto__.Person = Person;
person.__proto__.getName = getName;
Auf diese Weise ändern wir jedoch das Object.prototype
, denn wenn wir ein JavaScript-Objekt mit literals ( { ... }
) erstellen , wird es basierend auf erstellt Object.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:
person.__proto__ = {
Person: Person,
getName: getName
};
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:
var propertiesObject = {
Person: Person,
getName: getName
};
var person = Object.create(propertiesObject);
Es wird ein neues JavaScript erstellt Object
und das propertiesObject
an das __proto__
Attribut angehängt. So stellen Sie sicher, dass Sie Folgendes tun können:
console.log(person.__proto__===propertiesObject); //true
Der schwierige Punkt hierbei ist jedoch, dass Sie Zugriff auf alle Eigenschaften haben, die __proto__
auf der ersten Ebene des person
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.
Die Methode apply () ruft eine Funktion mit einem bestimmten Wert und Argumenten auf, die als Array (oder als Array-ähnliches Objekt) bereitgestellt werden.
und
Die Methode call () ruft eine Funktion mit einem bestimmten Wert und Argumenten auf, die einzeln angegeben werden.
Auf diese Weise, die mein Favorit ist, können wir unsere Funktionen leicht aufrufen wie:
Person.call(person, "George");
oder
//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);
getName.call(person);
getName.apply(person);
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:
function Person(name){ this.name = name; }
my_person_prototype = { getName: function(){ console.log(this.name); } };
In diesem Teil werde ich versuchen, alle Schritte auszuführen, die JavaScript unternimmt, ohne das new
Schlüsselwort zu verwenden und prototype
wenn Sie das new
Schlüsselwort verwenden. Wenn wir dies tun new 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:
var newObject = {};
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.
for(var key in my_person_prototype){
newObject[key] = my_person_prototype[key];
}
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:
var newObject = Object.create(my_person_prototype);
//here you can check out the __proto__ attribute
console.log(newObject.__proto__ === my_person_prototype); //true
//and also check if you have access to your desired properties
console.log(typeof newObject.getName);//"function"
Jetzt können wir die getName
Funktion in unserem aufrufen my_person_prototype
:
newObject.getName();
c. dann gibt es dieses Objekt dem Konstruktor,
Wir können dies mit unserer Probe tun wie:
Person.call(newObject, "George");
oder
Person.apply(newObject, ["George"]);
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:
new FunctionName()
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 , ist Object.prototype
Gegenstand:
console.log(Object.prototype.__proto__===null);//true
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.