Warum wird von der Verwendung von Konstruktoren beim Erstellen von Prototypen abgeraten?

10

Kurzer Hintergrund: In JavaScript hat die Konstruktorfunktion für jeden Objekttyp eine prototypeEigenschaft. Das prototypebezieht sich auf ein Objekt, das jedes konstruierte Objekt als nächsten Schritt in seiner Prototypenkette verwendet. Wenn ein Typ einem anderen Typ inhärent sein soll, können Sie prototypeden untergeordneten Typ auf eine neue Instanz des übergeordneten Typs setzen.

Zum Beispiel:

var Parent = function() { /* constructor business */ }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = /*** !! Some prototype object goes here !! ***/

Meine Frage fragt, welcher Code an der Stelle " Some prototype object goes here" im obigen Code stehen soll. Mein erster Instinkt ist, eine Instanz des übergeordneten Elements (dh new Parent()) zu erstellen, aber in einem Kommentar zu einer Antwort auf Ist dies eine sichere Möglichkeit, einen Objektprototyp auf einen anderen zu kopieren? schreibt ein Benutzer:

Nein, nicht new bar()für das Prototypobjekt verwenden!

(... das ist eine Meinung, die ich in vielen SO-Antworten und Kommentaren gesehen habe, aber dies ist das einzige Beispiel, das ich derzeit zur Hand habe.)

Die andere Option ist die Verwendung Object.create(Parent.prototype)als Child.prototype. Soweit ich weiß, wird dadurch auch eine neue ParentInstanz erstellt, der ParentKonstruktor wird jedoch nicht ausgeführt .

Kann jemand erklären, warum das Ausführen der Konstruktorfunktion vermieden werden sollte, wenn ein Prototypobjekt aus einem übergeordneten Typ generiert wird? Gibt es ein erhebliches technisches Problem (möglicherweise bei mehreren Vererbungsebenen)? Oder ist ein solches Muster ein Missbrauch von Konstruktoren, der mit einigen prototypischen Best Practices kollidiert (z. B. wenn das Ausführen des Konstruktors beim Erstellen eines Prototyps gegen eine gewisse Trennung von Bedenken verstößt)?

Apsiller
quelle

Antworten:

5

Weil es eine Funktion ist, die nicht aufgerufen werden muss. newunterscheidet sich nicht wesentlich von einem regulären Funktionsaufruf in Javascript.

Ein Konstruktor kann mehr als nur Felder festlegen. Wenn beispielsweise eingehende Daten validiert werden, verursachen Sie einen Validierungsfehler, wenn Sie lediglich versuchen, die Vererbungskette festzulegen.

Und das brauchen Sie nicht Object.create, das reicht:

function objectCreate( proto ) {
    function T(){}
    T.prototype = proto;
    return new T();
}
Esailija
quelle
Aber genau so Object.createwird es umgesetzt.
Casey Chu
@CaseyChu überhaupt nicht. Und ich habe es erwähnt, weil in dem verlinkten Beitrag jemand sagte " Object.createfunktioniert nicht in IE8" - was nur ein nutzloser Kommentar ist, wenn Sie ihn für diesen Anwendungsfall in 2 Sekunden in jedem Browser implementieren können.
Esailija
2

Nachdem sich mein Verständnis etwas erweitert hat, möchte ich auf Esailijas Antwort mit einem konkreten Beispiel aufbauen :

Ein besonderes Problem besteht darin, dass ein Konstruktor instanzspezifische Eigenschaften festlegen kann. Wenn Sie also ein Prototypobjekt verwenden, das mit erstellt wurde new, können alle Ihre untergeordneten Instanzen eine einzige vom Konstruktor definierte instanzspezifische Eigenschaft des Prototyps gemeinsam nutzen.

Angenommen, ParentInstanzen haben jeweils eine eindeutige idEigenschaft als Erstellungszeit festgelegt:

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = new Parent();

Dies führt dazu, dass alle Child Instanzen eine einzelne Prototyp- idEigenschaft gemeinsam nutzen, die von dem einzigen new Parent()Objekt geerbt wurde, das als verwendet wird Child.prototype.

Ein besserer Ansatz für diesen Fall besteht darin, Object.createden übergeordneten Konstruktor (falls erforderlich) im untergeordneten Konstruktor zu verwenden und direkt aufzurufen:

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() {
    // run `this` through the Parent constructor function
    Parent.apply(this, arguments);
}
Child.prototype = Object.create(Parent.prototype);
Apsiller
quelle