Cuándo usar la programación prototípica en JavaScript

15

He dedicado bastante tiempo a desarrollar widgets simples para proyectos de la siguiente manera:

var project = project || {};

(function() {

  project.elements = {
    prop1: val1,
    prop2: val2
  }

  project.method1 = function(val) {
    // Do this
  }

  project.method2 = function(val) {
    // Do that
  }

  project.init = function() {
    project.method1(project.elements.prop1)
    project.method2(project.elements.prop2)
  }
})()

project.init();

Pero he empezado a cambiar mi formato a lo siguiente:

function Project() {
  this.elements = {
    prop1: val1,
    prop2: val2
  }

  this.method_one(this.elements.prop1);
  this.method_two(this.elements.prop2);
}

Project.prototype.method_one = function (val) {
  // 
};

Project.prototype.method_two = function (val) {
  //
};

new Project();

Por supuesto, estos son ejemplos tontos, así que no te envuelvas alrededor del eje. Pero, ¿cuál es la diferencia funcional y cuándo debo elegir una u otra?

    
pregunta JDillon522 13.02.2015 - 20:57
fuente

1 respuesta

6

La primera diferencia se puede resumir como: this se refiere a la Instancia de la clase. prototype se refiere a Definición .

Digamos que tenemos la siguiente clase:

var Flight = function ( number ) { this.number = number; };

Así que aquí adjuntamos this.number a cada instancia de la clase, y tiene sentido porque cada Flight debería tener su propio número de vuelo.

var flightOne = new Flight( "ABC" );
var flightTwo = new Flight( "XYZ" );

En contraste, prototype define una propiedad única a la que pueden acceder todas las instancias.

Ahora, si queremos obtener el número de vuelo, simplemente podemos escribir el siguiente fragmento de código y todas nuestras instancias obtendrán una Referencia para este objeto con un nuevo prototipo.

Flight.prototype.getNumber = function () { return this.number; };

La segunda diferencia es sobre la forma en que JavaScript busca una propiedad de un objeto. Cuando busca Object.whatever , JavaScript va hasta el objeto principal Object (el objeto del que todo lo demás ha heredado), y tan pronto como encuentre una coincidencia, regresará o llámalo.

Pero eso solo sucede con las propiedades prototipadas. Entonces, si tienes un lugar en los niveles más altos this.whatever , JavaScript no lo considerará como una coincidencia y continuará la búsqueda.

Veamos cómo sucede en la realidad.

Primero, tenga en cuenta que [casi] todo son Objetos en JavaScript. Prueba esto:

typeof null

Ahora veamos lo que está dentro de un Object (note la mayúscula O y . al final). En las Herramientas de desarrollo de Google Chrome, cuando ingrese . obtendrá una lista de propiedades disponibles dentro de ese objeto específico.

Object.

Ahora haga lo mismo para Function :

Function.

Puede observar el método name . Solo ve y enciéndelo y veamos que pasa:

Object.name
Function.name

Ahora vamos a crear una función:

var myFunc = function () {};

Y veamos si también obtuvimos el método name aquí:

myFunc.name

Deberías obtener una cadena vacía, pero está bien. No debes obtener un error o excepción.

Ahora, agreguemos algo a ese Object parecido a un dios y veamos si lo obtenemos en otros lugares también.

Object.prototype.test = "Okay!";

Y ahí tienes:

Object.prototype.test
Function.prototype.test
myFunc.prototype.test

En todos los casos debería ver "Okay!" .

En cuanto a los pros y los contras de cada método, puede considerar la creación de prototipos como una forma "más eficiente" de hacer las cosas, ya que mantiene una referencia en cada instancia en lugar de copiar la propiedad completa en cada objeto. Por otro lado, es un ejemplo de Tightly Coupling que es un gran no-no hasta que realmente puedas justificar la razón. this es bastante más complicado ya que es relevante para el contexto. Puede encontrar una gran cantidad de buenos recursos de forma gratuita en Internet.

Dicho de otra manera, ambas formas son solo herramientas de lenguaje y realmente dependen de ti y del problema que intentas resolver para elegir lo que mejor se ajusta.

Si necesita tener una propiedad que sea relevante para cada instancia de una clase, entonces use this . Si necesita tener una propiedad para funcionar igual en cada instancia, entonces use prototype .

Actualizar

Con respecto a los fragmentos de muestra, el primero es un ejemplo de Singleton , por lo que tiene sentido usar this dentro del cuerpo del objeto. También puedes mejorar tu ejemplo haciéndolo modular así (y no necesitas usar siempre también this ).

/* Assuming it will run in a web browser */
(function (window) {
    window.myApp = {
        ...
    }
})( window );

/* And in other pages ... */
(function (myApp) {
    myApp.Module = {
        ...
    }
})( myApp );

/* And if you prefer Encapsulation */
(function (myApp) {
    myApp.Module = {
         "foo": "Foo",
         "bar": function ( string ) {
             return string;
         },
         return {
             "foor": foo,
             "bar": bar
         }
    }
})( myApp );

Tu segundo fragmento de código no tiene mucho sentido porque primero estás usando this y luego intentas hackearlo con prototype , lo que no funciona porque this tiene prioridad sobre prototype . No estoy seguro de cuáles eran sus expectativas con respecto a ese código y de cómo funcionaba, pero le recomiendo que lo refactorice.

Actualizar

Para desarrollar más detalladamente que this tiene prioridad sobre prototype , puedo mostrarle un ejemplo y explicarle cómo se puede explicar, pero no tengo ningún recurso externo para respaldarlo.

El ejemplo es muy simple:

var myClass = function () { this.foo = "Foo"; };
myClass.prototype.foo = "nice try!";
myClass.prototype.bar = "Bar";

var obj = new myClass;
obj.foo;     // Still contains "Foo" ...
obj.bar;     // Contains "Bar" as expected

La explicación es, como sabemos, this es relevante para el contexto. Así que no llegará a existir hasta que el contexto esté listo. Cuando el contexto está listo? Cuando se está creando la nueva instancia! ¡Deberías adivinar el resto ahora! Esto significa que aunque hay una definición prototype , pero this tiene más sentido tener prioridad porque se trata de la nueva instancia que se está creando en ese momento.

    
respondido por el 53777A 17.02.2015 - 10:55
fuente

Lea otras preguntas en las etiquetas