JavaScript è un linguaggio OOP basata su prototipi e non classi. Questa è una delle cause di tutta questa confusione che si può vedere in giro: molti sviluppatori usano JS come se fosse una classe.
Pertanto, è possibile visualizzare molte librerie che tentano di utilizzare il paradigma di un linguaggio basato su classi in JS.
Inoltre, a JS mancano alcuni tratti che rendono l'ereditarietà, anche basata sul prototipo, dolorosa. Ad esempio, prima di non c'era un modo per creare un oggetto da un altro oggetto (come dovrebbe fare un linguaggio basato sul prototipo OOP), ma usando solo un costruttore function
.
E anche per questo motivo, è possibile vedere un sacco di librerie che stanno cercando di "risolvere" il linguaggio, ognuno a suo modo.
Quindi, la tua confusione è normale. Diciamo che, il modo "ufficiale" è usare la proprietà prototype
, function
s come costruttore e Object.create
per creare dall'istanza dell'oggetto. Tuttavia, come detto sopra, in alcuni casi il codice è prolisso o privo di funzionalità, quindi questa procedura viene spesso inserita in qualche modo, e quindi diventa una questione di gusto personale.
Perché stai parlando di modello, puoi dare un'occhiata a Backbone's Model e vedere se questo approccio si adatta.
Aggiornamento: per dare qualche esempio che spero vi aiuta a chiarire, ecco il modo in cui la scuola eredità vecchio usando 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();
Ora, qui i problemi:
- Il costruttore di
Model
viene chiamato una volta, solo quando è impostato RestModel.prototype
. Pertanto, la proprietà foo
per ogni istanza di RestModel
sarà "foo".
- Non solo, ma tutte
RestModel
le istanze condivideranno la stessa istanza dello stesso array nella proprietà this.array
. Se crei direttamente un'istanza di , hai una nuova istanza di array per ogni istanza.
myModel.constructor
è Model
anziché RestModel
. Questo perché sostituiamo prototype
con una nuova istanza di Model
, che contiene constructor
uguale a Model
.
- Se si desidera avere una nuova istanza di
RestModel
con una chiamata lenta al costruttore, non è possibile.
Penso che ci siano i punti principali, ovviamente non sono gli unici. Quindi, come risolvere questi problemi? Come ho detto, molte persone lo hanno già fatto, e creano anche librerie e framework per limitare la verbosità. Tuttavia, per avere un'idea:
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);
Si noti che se non si desidera utilizzare o prototype
function
come costruttore, con Object.create
si può fare:
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);
Oppure:
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 questo caso si imita fondamentalmente il costruttore. È anche possibile passare un descriptor
a Object.create
(vedere lo docs) ma diventa più dettagliato. La maggior parte delle persone usa una sorta di funzione o metodo extend
(come probabilmente avete visto nell'esempio Backbone).
Spero che aiuti!
Perché in questo caso 'Object.Create' è migliore di' nuovo'? E se volessi supportare anche i costruttori? E che il costruttore viene chiamato sia in 'RestModel' che in' Model' (se creo un 'RestModel'). Normalmente sono un dev di C#, quindi non ho davvero la differenza. Voglio definire il prototipo di base e utilizzare un costruttore, ma non capisco come ottenerli entrambi? – jgauffin
Penso che questa risposta lo riassuma con * "Usa ciò che è appropriato." * A volte vuoi la logica nel costruttore, a volte no. +1 –