2012-06-05 18 views
13

He estado leyendo muchos artículos sobre "herencia" en javascript. Algunos de ellos usan new, mientras que otros recomiendan Object.Create. Cuanto más leo, más me confundo, ya que parece existir una cantidad interminable de variantes para resolver la herencia.Corrección de la herencia de JavaScript

¿Alguien puede ser amable para mostrarme la forma más aceptada (o estándar de facto si hay una)?

(I desea tener un objeto base Model que puedo extender RestModel o LocalStorageModel.)

Respuesta

11

simple: Object.create no está soportada en todos los ambientes, pero puede ser calzar con new. Aparte de eso, los dos tienen diferentes objetivos: Object.create solo crea un Objeto que hereda de otro, mientras que newtambién invoca una función de constructor. Usa lo que es apropiado

En su caso, parece querer que RestModel.prototype herede de Model.prototype. Object.create (o su cuña) es la forma correcta pues, porque no quiere a) crear una nueva instancia (una instancia de un new Model) yb) no quiere llamar al constructor del modelo:

RestModel.prototype = Object.create(Model.prototype); 

Si desea llamar al constructor del modelo en RestModels, que no tiene nada que ver con los prototipos. Utilice call() o apply() para ello:

function RestModel() { 
    Model.call(this); // apply Model's constructor on the new object 
    ... 
} 
+0

¿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

+1

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 –

10

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:

  1. 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".
  2. No solo eso, sino todosRestModel 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.
  3. 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.
  4. 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!

+0

¿Qué ejemplo me recomienda que use? – jgauffin

+0

Todos ellos son válidos, pero en una forma u otra terminarán siendo prolijos. Puede generar imágenes si 'RestModel' tiene muchas propiedades o métodos nuevos, por ejemplo. De eso estaba hablando cuando dije que a JS todavía le falta algo. Para eliminar la verbosidad, o decide usar bibliotecas de terceros, o crea un conjunto de funciones de utilidad para hacer eso. Evitaré el enfoque "nuevo" puro (el primero), y simplemente decidí por el 2º o el 3º, depende si te sientes más cómodo teniendo algo que "se asemeje" a una "clase" (por lo tanto, el 2º) o no (3º)) – ZER0