JavaScript es un lenguaje de programación orientada a objetos basado en prototipos y no clases. Esa es una de las causas de toda esta confusión que se puede ver a su alrededor: muchos desarrolladores usan JS ya que se basó en una clase.
Por lo tanto, puede ver muchas bibliotecas que tratan de usar el paradigma de un lenguaje basado en clases en JS.
Además, a JS le faltan algunos rasgos que hacen que la herencia, también basada en prototipos, sea dolorosa. Por ejemplo, antes de Object.create
no había una manera de crear un objeto desde otro objeto (como debería hacerlo un lenguaje basado en prototipos de OOP), pero solo usando un function
como constructor.
Y también por esa razón, puede ver muchas bibliotecas que intentan "arreglar" el lenguaje, cada una a su manera.
Entonces, su confusión es normal. Digamos que la forma "oficial" es usar la propiedad prototype
, function
s como constructor y Object.create
para crear desde la integridad del objeto. Sin embargo, como se dijo anteriormente, en algunos casos el código es detallado o carece de funcionalidad, por lo que este procedimiento a menudo se envuelve de alguna manera, y luego se convierte en una cuestión de gusto personal.
Porque estás hablando de modelo, puedes echarle un vistazo al Backbone's Model y ver si este enfoque te queda bien.
actualización: dar algún ejemplo que espero que ayuda a clarificar, aquí la manera antigua herencia escuela 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();
Ahora, aquí los temas:
- El constructor de
Model
se llama una vez, solo cuando se establece RestModel.prototype
. Por lo tanto, la propiedad foo
para cada instancia de RestModel
será "foo".
- No solo eso, sino todos
RestModel
instancias compartirán la misma instancia de la misma matriz en la propiedad this.array
. Si crea una instancia de Model
directamente, tiene una nueva instancia de matriz para cada instancia.
myModel.constructor
es Model
en lugar de RestModel
. Eso es porque anulamos prototype
con una nueva instancia de Model
, que contiene constructor
igual a Model
.
- Si desea tener una nueva instancia de
RestModel
con una llamada perezosa al constructor, no es posible.
Creo que hay puntos principales, por supuesto que no son los únicos. Entonces, ¿cómo resolver esos problemas? Como dije, muchas personas ya lo hicieron y crean bibliotecas y marcos de trabajo para limitar la verbosidad. Sin embargo, para tener una 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);
Tenga en cuenta que si usted no desea utilizar prototype
o function
como constructor, con Object.create
se puede hacer eso:
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);
O:
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();
En ese caso, usted imita básicamente al constructor. También puede pasar descriptor
a Object.create
(vea docs) pero se vuelve más detallado. La mayoría de las personas usa una clase de función o método extend
(como probablemente haya visto en el ejemplo de Backbone).
Espero que ayude!
¿Por qué 'Object.Create' es mejor que' new' en ese caso? ¿Y si también quisiera apoyar constructores? Y que el constructor recibe una llamada tanto en 'RestModel' como' Model' (si creo un 'RestModel'). Normalmente soy un desarrollador de C#, así que realmente no entiendo la diferencia. Quiero definir el prototipo base y usar un constructor, pero no entiendo cómo puedo obtener ambos? – jgauffin
Creo que esta respuesta lo resume con * "Use lo que sea apropiado". * A veces quiere la lógica en el constructor, a veces no. +1 –