2008-12-31 22 views
7

Veo una gran cantidad de código como este:de la herencia de prototipo en JavaScript

function Base() {} 
function Sub() {} 
Sub.prototype = new Base(); 

Sin embargo, si lo hace:

s = new Sub(); 
print(s.constructor == Sub); 

Esto es falso. Esto me parece confuso, ya que el constructor de s es, de hecho, Sub. ¿Es convencional/mejor hacer esto?

function Base() {} 
function Sub() {} 
Sub.prototype = new Base(); 
Sub.prototype.constructor = Sub; 

¿o realmente no importa?

+0

Acabo de ejecutar la comparación a través de una página html como alerta (s.constructor == Sub) y devolvió verdadero. –

+0

Muchos marcos ajustan la propiedad 'constructor' apuntar correctamente al constructor de la subclase. Tengo una publicación que trata este y otros problemas en el código que mostraste arriba. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html –

Respuesta

9

'constructor' no hace lo que se ve como lo hace. Esto, además de su falta de uniformidad, es una buena razón para evitar usarlo: seguir con instanceof y prototipo.

Técnicamente: 'constructor' no es una propiedad de la instancia 's', es una propiedad del objeto prototipo 'Sub' que se ve a través de. Cuando creas la función 'Sub' en Mozilla, obtienes un objeto Sub.prototype por defecto recién creado que tiene un 'constructor' apuntando hacia atrás a la función Sub como cortesía.

Sin embargo, luego reemplaza ese prototipo con una nueva Base(). El prototipo original por defecto con el enlace de regreso a Sub se pierde; en su lugar, Sub.prototype es una instancia de Base sin ninguna propiedad ancestral de 'constructor'. Entonces:

new Sub().constructor=== 
Sub.prototype.constructor=== 
new Base().constructor=== 
Base.prototype.constructor=== 
Base 

... hasta el objeto más básico cuyo prototipo no se modificó.

¿Es convencional/mejor hacer esto?

Cuando se trata de objetos/clases de JavaScript no existe una convención; el sistema de metaclase de cada biblioteca se comporta de forma ligeramente diferente. No he visto uno que escriba 'constructor' para cada clase derivada manualmente, pero parece una solución tan buena como cualquiera si realmente quieres tener el constructor real disponible; también hará que el código sea compatible con navegadores/motores que no le dan 'constructor'.

Consideraría darle un nombre diferente, sin embargo, para evitar confusiones con la propiedad 'constructor' existente y de comportamiento diferente.

3

Si desea probar si un objeto es exactamente una instancia de Sub utilizar el instanceof operador: -

print(s instanceof Sub); 

Si desea saber si un objeto es una instancia de Sub o una instancia de un sub -class de Sub utilizar el método isPrototypeOf: -

print(Sub.prototype.isPrototypeOf(s)); 
+0

gracias por el consejo, tiene sentido. – Claudiu

+0

Otra buena Anthony;) – Rob

1

Sí,

Sub.prototype.constructor = Sub; 

de utiliza instanceof pero hay una solución mejor let. Mire aquí:, TDD JS Inheritance on GitHub, y encuentre Parasitic Combination Herencia patrón. El código está TDD'd así que deberías poder asimilarlo rápidamente y luego simplemente cambiar los nombres para que comiences. Esto es básicamente lo que usa YAHOO.lang.extend (fuente: empleado y autor de yahoo Nicholas Zakas's Professional JavaScript for Web Developer's, 2nd ED, page 181). Buen libro por cierto (¡no afiliado de ninguna manera!)

¿Por qué? Debido a que el patrón clásico con el que está trabajando tiene vars de referencia staticy (si crea var arr = [1,2] en el objeto base, TODAS las instancias tendrán lectura/escritura y "compartirán estado" de 'arr'! use constructor stealing puede evitar esto. Vea mis ejemplos.

Cuestiones relacionadas