2010-08-28 10 views
5

En JavaScript, lo mismo que puede hacer de muchas maneras diferentes.Prototipos en JavaScript

Considere los ejemplos:

1:

function Circle(radius) { 
return { 
    "r" : radius, 
    "area" : function(){ 
    return Circle.pi * this.r * this.r; 
    } 
} 
} 
Circle.pi = 3.14159; 

var a = Circle(10); 
alert(a.area()); 

2:

function Circle(radius) { 
    this.r = radius; 
} 

Circle.pi = 3.14159; 
Circle.prototype.area = function(){ 
return Circle.pi * this.r * this.r; 
} 

var a = new Circle(10); 
alert(a.area()); 

El segundo es mejor que la primera, porque nosotros no definir la misma función área para cualquier instancia de Círculo.

Pero vamos a considerar 3:

function Circle(radius) { 
return { 
    "r" : radius, 
    "area" : Circle.area 
} 
} 
Circle.pi = 3.14159; 
Circle.area = function(){ 
return Circle.pi * this.r * this.r; 
} 

var a = Circle(10); 
alert(a.area()); 

¿Hay alguna razón para preferir segundo estilo en lugar de tercero? ¿O entendí mal algo?

+0

Conoces la disponibilidad de ['Math.PI'] (https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Math/PI), ¿no? –

+1

posible duplicado de [javascript orientado a objetos con prototipos vs cierres] (http://stackoverflow.com/questions/3564238/object-oriented-javascript-with-prototypes-vs-closures) –

+0

He hecho algunos puntos de referencia como aquí http : //blogs.msdn.com/b/kristoffer/archive/2007/02/13/javascript-prototype-versus-closure-execution-speed.aspx. El resultado: el 3er estilo entre el 1 y el 2 :) Gracias por todas las respuestas y comentarios, he aprendido mucho. – Dan

Respuesta

4

Sin duda con el ejemplo 2. Ni el ejemplo 1 o 3 hacen un buen uso de características orientadas a objetos de JavaScript porque:

  1. duplica definiciones de métodos en cada caso.
  2. Al devolver un objeto nuevo en lugar de usar this, pierde la identidad de la clase, es decir, ya no puede hacer comprobaciones como a instanceof Circle.
  3. Olvidas la posibilidad de herencia ya que no usas prototipos.
1

La diferencia entre Circle.prototype.area y Circle.area es que solo se puede acceder a ella con una instancia de la clase.

Circle.prototype.area = function(){}; 
Circle.area // wrong 
(new Circle()).area // ok (you need a Circle object) 

y

Circle.area = function(){}; 
Circle.area // ok (you don't need the object, its static) 
(new Circle()).area // wrong 
+0

¿Has leído el tercer ejemplo de OP? –

+1

No del todo cierto. Lo siguiente es legal: 'Circle.prototype.area()' (aunque probablemente quiera usar 'call' o' apply' con este.) –

+0

Cierto, pero si se trata de un prototipo en general, no debería llamarse así, podría depender de algunas propiedades de la instancia. De todos modos, gracias por señalar eso. – BrunoLM

0

El problema con el ejemplo 2 se, que cuando accidentalmente olvidó usar el operador new al crear el objeto, y sólo llame var a = Circle(10); (lo cual está bien para la tercera ejemplo, pero no para el segundo), entonces su constructor crea un gran problema:

this.r = radius; 

Dado que no se ha utilizado new, this se le asignará el objeto global, por lo que el constructor realmente establece la variable global r!

Así que yo prefiero fuertemente ejemplo 3.

2

¿Hay alguna razón para preferir segundo estilo en lugar de tercero?

La tercera estilo todavía está perdiendo una cantidad pequeña de espacio con el fin de almacenar la asociación entre el nombre area y la función de área.

También porque está devolviendo un nuevo Object del literal {...}, instanceof Circle no funcionará.

El segundo es mejor que el primero porque no definimos el mismo área de función para ninguna instancia del círculo.

hecho, pero puede a veces ser útil para definir una nueva copia de cada método de una copia que, gracias a los cierres, pueden saber de qué objeto se ve obligada a. Con el prototipado tradicional, solo obtiene el contexto this que se establece a partir del objeto desde el cual el llamador lo recuperó, en lugar de estar vinculado a un objeto en particular.La primera forma evita los problemas de this -la retención en cosas como los controladores de eventos, a costa de una cierta pérdida de eficiencia.

0

Me gustaría comentar sobre "El segundo es mejor que el primero porque no definimos el mismo área de función para ninguna instancia del Círculo". En la práctica, esto puede ser una ventaja tan insignificante como para ser totalmente insignificante. Tiendo a favorecer la sintaxis y el código amigable con el hombre sobre la eficiencia, , a menos que el rendimiento se vea afectado notoriamente. He estado ignorando por completo la función Prototype de JavaScript y también evitando el uso de "esto", básicamente usando la técnica n.º 1. Está funcionando bien para mí. Me parece que evitar "esto" evita mucha confusión sobre a qué se refiere "esto". Es perfectamente posible crear estructuras de tipo herencia sin "prototipo". Puede crear un objeto de superclase y anular los métodos que desee. Douglas Crockford ha escrito bastante extensamente sobre numerosas formas diferentes de hacer herencia en javascript.

Estoy de acuerdo con casablanca de que el hecho de poder probar el tipo usando "instanceof" es una buena ventaja de devolver "esto". Tal vez eche otro vistazo a "protype" y "this" en un proyecto futuro. Por ahora, sin embargo, me llevo bien sin ellos.

+1

En cuanto a 'this': también lea Peter Michaux '[JavaScript Widgets Without this this]"] (http://michaux.ca/articles/javascript-widgets-without-this) –

Cuestiones relacionadas