Ich habe viele Artikel über “Vererbung” in Javascript gelesen. Einige von ihnen verwendet new
während andere es empfehlen Object.Create
. Je mehr ich lese, desto verwirrter werde ich, da es unendlich viele Varianten zu geben scheint, um das Thema Vererbung zu lösen.
Kann mir jemand freundlicherweise den akzeptiertesten Weg zeigen (oder den Defacto-Standard, falls es einen gibt)?
(Ich möchte ein Basisobjekt haben Model
die ich verlängern kann RestModel
oder LocalStorageModel
.)
Einfach: Object.create
wird nicht in allen Umgebungen unterstützt, kann aber angepasst werden new
. Abgesehen davon haben die beiden unterschiedliche Ziele: Object.create
erstellt nur ein Objekt, das von einem anderen erbt, während new
Auch ruft eine Konstruktorfunktion auf. Verwenden Sie, was angemessen ist.
In deinem Fall scheinst du das zu wollen RestModel.prototype
erbt von Model.prototype
. Object.create
(oder sein Shim) ist dann der richtige Weg, weil Sie nicht a) eine neue Instanz erstellen (einen instanziieren möchten new Model
) und b) den Modellkonstruktor nicht aufrufen möchten:
RestModel.prototype = Object.create(Model.prototype);
Wenn Sie den Modellkonstruktor auf RestModels aufrufen möchten, hat das nichts mit Prototypen zu tun. Verwenden call()
oder apply()
dafür:
function RestModel() {
Model.call(this); // apply Model's constructor on the new object
...
}
JavaScript ist eine OOP-Sprache, die auf Prototypen und nicht auf Klassen basiert. Das ist einer der Gründe für all diese Verwirrung, die Sie sehen können: Viele Entwickler verwenden JS, da es klassenbasiert war.
Daher können Sie viele Bibliotheken sehen, die versuchen, das Paradigma einer klassenbasierten Sprache in JS zu verwenden.
Darüber hinaus fehlen JS selbst einige Eigenschaften, die die Vererbung, auch prototypbasiert, schmerzhaft machen. Zum Beispiel vorher Object.create
Es gab keine Möglichkeit, ein Objekt aus einem anderen Objekt zu erstellen (wie es eine auf OOP-Prototypen basierende Sprache tun sollte), sondern nur die Verwendung von a function
als Konstrukteur.
Und auch aus diesem Grund gibt es viele Bibliotheken, die versuchen, die Sprache zu „reparieren“, jede auf ihre eigene Art und Weise.
Deine Verwirrung ist also normal. Sagen Sie, der “offizielle” Weg ist die Verwendung prototype
Eigentum, function
s als Konstruktor und Object.create
aus der Instanz des Objekts erstellen. Wie oben erwähnt, ist der Code jedoch in einigen Fällen ausführlich oder es fehlt ihm an Funktionalität, sodass diese Prozedur oft irgendwie umbrochen wird und dann eine Frage des persönlichen Geschmacks wird.
Da Sie von Modell sprechen, können Sie einen Blick darauf werfen Backbone-Modell und sehen Sie, ob dieser Ansatz zu Ihnen passt.
Aktualisieren: Um ein Beispiel zu geben, von dem ich hoffe, dass es Ihnen hilft, es zu verdeutlichen, verwenden Sie hier die alte Schule der Vererbung new
:
function Model() {
this.foo = "foo";
this.array = [];
}
Model.prototype.foo = "";
Model.prototype.array = null;
Model.prototype.doNothing = function() {};
function RestModel() {
this.bar = "bar";
}
RestModel.prototype = new Model;
RestModel.prototype.bar = ""
var myModel = new RestModel();
Hier nun die Probleme:
- Der Konstrukteur von
Model
wird einmal aufgerufen, nur wenn die RestModel.prototype
eingestellt ist. deshalb, die foo
Eigentum für alle RestModel
Instanz wird “foo” sein.
- Nicht nur das, sondern alle
RestModel
Instanzen teilen sich dieselbe Instanz desselben Arrays in this.array
Eigentum. Wenn Sie eine Instanz von erstellen Model
direkt haben Sie für jede Instanz eine neue Instanz des Arrays.
myModel.constructor
ist Model
anstatt RestModel
. Das liegt daran, dass wir überschreiben prototype
mit einer neuen Instanz von Model
das beinhaltet constructor
ist gleich Model
.
- Wenn Sie eine neue Instanz von haben möchten
RestModel
mit einem faulen Aufruf des Konstruktors, ist nicht möglich.
Ich denke, es gibt die Hauptpunkte, natürlich sind sie nicht die einzigen. Also, wie kann man diese Probleme lösen? Wie gesagt, viele Leute haben das bereits getan, und sie erstellen Bibliotheken und Frameworks, um die Ausführlichkeit einzuschränken. Aber um eine Idee zu haben:
function Model() {
this.foo = "foo";
this.array = [];
}
Model.prototype.foo = "";
Model.prototype.array = null;
Model.prototype.doNothing = function() {};
function RestModel() {
Model.call(this);
this.bar = "bar";
}
RestModel.prototype = Object.create(Model.prototype);
RestModel.prototype.constructor = RestModel;
RestModel.prototype.bar = ""
var myModel = new RestModel();
// for lazy constructor call
var anotherModel = Object.create(RestModel.prototype);
RestModel.call(anotherModel);
Beachten Sie, dass, wenn Sie nicht verwenden möchten prototype
oder function
als Konstruktor, mit Object.create
Das kannst du machen:
var Model = {
foo: "",
array: null,
doNothing: function() {}
}
var RestModel = Object.create(Model);
RestModel.bar = "";
var myModel = Object.create(RestModel);
// Assuming you have to set some default values
initialize(RestModel);
Oder:
var Model = {
foo: "",
array: null,
doNothing: function() {},
init : function () {
this.foo = "foo";
this.array = [];
},
}
var RestModel = Object.create(Model);
RestModel.bar = "";
RestModel.init = function () {
Model.init.call(this);
this.bar = "bar";
}
var myModel = Object.create(RestModel);
myModel.init();
In diesem Fall ahmen Sie im Grunde den Konstruktor nach. Sie können auch eine passieren descriptor
zu Object.create
(siehe die Dokumente), aber es wird ausführlicher. Die meisten Leute verwenden eine Art von extend
Funktion oder Methode (wie Sie wahrscheinlich im Backbone-Beispiel gesehen haben).
Ich hoffe es hilft!