tipos heredar ejemplos definicion clases javascript oop

heredar - Declarando el método del objeto javascript en la función del constructor vs. en el prototipo



super js (3)

La gran mayoría del código javascript que he visto utiliza el método prototipo. Creo que hay tres razones para esto que puedo pensar en la parte superior de mi cabeza.

La primera es que evitas que cada clase sea un gran constructor: la lógica constructora entra en la función constructora, la lógica para otros métodos se declara en otra parte; esto es principalmente una cosa de claridad / separación de preocupaciones, pero en javascript necesitas todo de claridad que puede tener en sus manos.

El segundo es la eficiencia. Cuando declaras métodos en el constructor, estás creando una nueva instancia del objeto función para cada instancia del objeto, y también vinculando el alcance del constructor a cada una de estas funciones (es decir, pueden hacer referencia, por ejemplo, al argumentos al constructor, que luego nunca pueden ser creados mientras el objeto viva). Cuando declara métodos en el prototipo, hay una sola copia del objeto de función que utilizan todas las instancias: las propiedades del prototipo no se copian en las instancias.

Una tercera razón es que puede "extender" una clase de varias maneras cuando utiliza el método prototipo, como el prototipo de encadenamiento utilizado por Backbone.js y la construcción de clase de CoffeeScript.

Esta pregunta ya tiene una respuesta aquí:

Al crear objetos javascript, puedo poner una declaración de método en la función constructora o en el prototipo. Por ejemplo, digamos que quiero una clase Dog que tenga una propiedad Name y un método Bark. Puedo poner la declaración del método Bark en la función constructora:

var Dog = function(name) { this.Name = name; this.Bark = function() { alert(this.Name + " bark"); }; }

o podría ponerlo como método en el objeto prototipo:

var Dog = function(name) { this.Name = name; } Dog.prototype.Bark = function() { alert(this.Name + " bark"); };

Cuando instanciamos objetos de tipo Dog, ambos enfoques parecen funcionar bien:

var dog = new Dog("Fido"); dog.Bark(); //Both approaches show "Fido bark"

¿Debo preferir uno de estos enfoques sobre el otro? ¿Hay alguna ventaja al usar una sobre la otra? Detrás de escena, ¿estos dos enfoques terminan haciendo exactamente lo mismo? ¿Qué enfoque tiende a favorecer la mayoría de las personas?

Gracias por la ayuda.


Los dos son diferentes: el primero almacenará la referencia al método solo en el objeto prototipo, mientras que la segunda solución almacenará el método en cada uno de los objetos. Esto significa que cada objeto contendrá un puntero adicional y, por lo tanto, ocupará un poco más de memoria cada uno.

El método por objeto permite que el método haga referencia a variables en el constructor (un cierre) y, por lo tanto, le permite acceder a algunos datos a los que no puede acceder desde un prototipo de métodos.

Finalmente, un método prototipo puede cambiarse más tarde , es decir, puede redefinir Bark en tiempo de ejecución en el objeto prototipo, y este cambio funcionará para todos los objetos con este prototipo (ya que el método siempre se busca a través del prototipo).


Para el ejemplo que das, debes usar el enfoque de prototipo. En general, depende. La principal ventaja del primer enfoque (métodos de inicialización en el constructor) es que puede aprovechar los cierres haciendo uso de variables locales definidas dentro del constructor en sus métodos. Estas variables no son directamente accesibles fuera de la función constructora, por lo que son efectivamente "privadas", lo que significa que su API es más limpia que si estas variables se definieran en su lugar como propiedades del objeto. Algunas reglas generales:

  • Si sus métodos no usan variables locales definidas en su constructor (su ejemplo no), entonces use el enfoque de prototipo.
  • Si está creando muchos Dog s, use el enfoque de prototipo. De esta forma, todas las "instancias" (es decir, objetos creados por el constructor Dog ) compartirán un conjunto de funciones, mientras que el modo constructor se crea un nuevo conjunto de funciones cada vez que se llama al constructor Dog utilizando más memoria.
  • Si está creando una pequeña cantidad de Dog y encuentra que el uso de variables locales, "privadas" en su constructor mejora su código, este puede ser el mejor enfoque. Use su juicio y haga algunos puntos de referencia si el rendimiento o el consumo de memoria son las principales preocupaciones.

Es posible utilizar un enfoque híbrido por el cual solo los métodos que necesitan acceso a las variables de constructor privadas locales se definen en el constructor mientras que otros métodos se asignan al prototipo.

Por ejemplo, el código a continuación utiliza una variable local en el constructor para realizar un seguimiento del número de veces que este perro ha ladrado manteniendo el número real en privado, por lo que los métodos relacionados con el ladrido se definen dentro del constructor. El movimiento de cola no requiere acceso a la cantidad de ladridos, por lo tanto, ese método se puede definir en el prototipo.

var Dog = function(name) { this.name = name; var barkCount = 0; this.bark = function() { barkCount++; alert(this.name + " bark"); }; this.getBarkCount = function() { alert(this.name + " has barked " + barkCount + " times"); }; }; Dog.prototype.wagTail = function() { alert(this.name + " wagging tail"); }; var dog = new Dog("Dave"); dog.bark(); dog.bark(); dog.getBarkCount(); dog.wagTail();