Foros del Web » Programando para Internet » Javascript »

Herencia y constructor

Estas en el tema de Herencia y constructor en el foro de Javascript en Foros del Web. Buenas. Acabo de encontrar un comportamiento que me parece extraño en Javascript y que no encuentro una respuesta. Defino una clase B y una clase ...
  #1 (permalink)  
Antiguo 09/07/2014, 13:00
 
Fecha de Ingreso: julio-2006
Ubicación: Barcelona
Mensajes: 244
Antigüedad: 15 años, 4 meses
Puntos: 32
Herencia y constructor

Buenas.

Acabo de encontrar un comportamiento que me parece extraño en Javascript y que no encuentro una respuesta.
Defino una clase B y una clase C que hereda de B.
Creo una instancia de C llamada c.
Llamo al método constructor desde c y, sin saber por qué, llama al constructor de B.

Aquí el código:
Código Javascript:
Ver original
  1. function B(){
  2.     this.b = 2;
  3.     console.log("B constructor");
  4. }
  5. B.prototype.fbb = function() { this.b++; }
  6.  
  7. function C(){
  8.     this.c = 3;
  9.     console.log("C constructor");
  10. }
  11. C.prototype = Object.create(B.prototype);
  12. C.prototype.fcc = function() {  this.c++ }
  13.  
  14. var c = new C(); // C constructor : OK
  15. console.log(c instanceof B); // ok
  16. console.log(c instanceof C); // ok
  17. c.constructor(); // B constructor : ????

¿Alguna explicación?
__________________
github.com/xgbuils | npm/xgbuils
  #2 (permalink)  
Antiguo 09/07/2014, 13:50
Avatar de marlanga  
Fecha de Ingreso: enero-2011
Ubicación: Murcia
Mensajes: 1.024
Antigüedad: 10 años, 10 meses
Puntos: 206
Respuesta: Herencia y constructor

La orientación a objetos de javascript siguiendo el paradigma de JAVA es emulada, pero no real. En la línea 12 estás machacando todos los atributos pertenecientes al prototipo de C por los de B, entre ellos, el atributo "constructor". Por eso los métodos de C hay que crearlos después de esa línea, sobre todo si tienen el mismo nombre que otro atributo de B (porque si lo declaras antes, el de B lo machacaría por la misma razón).

Si quieres recuperar el atributo "constructor" original, pon un C.prototype.constructor = C; justo después de la línea 12, aunque yo no uso nunca el constructor; directamente hago un new C(...) y a correr.
  #3 (permalink)  
Antiguo 09/07/2014, 15:30
Avatar de stock  
Fecha de Ingreso: junio-2004
Ubicación: Monterrey NL
Mensajes: 2.390
Antigüedad: 17 años, 5 meses
Puntos: 53
Respuesta: Herencia y constructor

Código Javascript:
Ver original
  1. C.prototype = Object.create(B.prototype);

Esa línea es la responsable, en lugar de eso deberías copiar cada propiedad de B a C individualmente, utilizando un for in por ejemplo.

Saludos
  #4 (permalink)  
Antiguo 10/07/2014, 09:26
 
Fecha de Ingreso: julio-2006
Ubicación: Barcelona
Mensajes: 244
Antigüedad: 15 años, 4 meses
Puntos: 32
Respuesta: Herencia y constructor

Gracias a los dos! Me quedo con la versión de marlanga Pues emula mejor la herencia:
Código Javascript:
Ver original
  1. Function.prototype.extend = function (base) {
  2.     this.prototype = Object.create(base.prototype);
  3.     this.prototype.constructor = this;
  4. }
  5.  
  6. function B(){
  7.     this.b = 2;
  8.     console.log("B constructor");
  9. }
  10. B.prototype.fbb = function() { this.b++; }
  11.  
  12. function C(){
  13.     this.c = 3;
  14.     console.log("C constructor");
  15. }
  16.  
  17. C.extend(B);
  18. C.prototype.fcc = function() {  this.c++ }
  19.  
  20. var c = new C(); // C constructor : OK
  21. console.log(c instanceof B); // ok
  22. console.log(c instanceof C); // ok
  23. c.constructor(); // C constructor : ok

En la de stock me devuelve falso al comprobar si c es una instancia de B.
Código Javascript:
Ver original
  1. Function.prototype.extend = function (base) {
  2.     for( var method in base.prototype ) {
  3.         this.prototype[method] = base.prototype[method];
  4.     }
  5. }
  6.  
  7. function B(){
  8.     this.b = 2;
  9.     console.log("B constructor");
  10. }
  11. B.prototype.fbb = function() { this.b++; }
  12.  
  13. function C(){
  14.     this.c = 3;
  15.     console.log("C constructor");
  16. }
  17.  
  18. C.extend(B);
  19. C.prototype.fcc = function() {     this.c++ }
  20.  
  21. var c = new C(); // C constructor : OK
  22. console.log(c instanceof B); // false <--- no emula bien la herencia
  23. console.log(c instanceof C); // ok
  24. c.constructor(); // C constructor : ok

Y ya que estamos. He leído ya varias veces que es una mala práctica modificar el prototype de los las clases preestablecidas de Javascript (cosa que he hecho con Function en este caso). La razón que se da es que le estamos dando un comportamiento nuevo a esas clase y otro programador que use el código se podría sentir confuso ante las variaciones. Yo no soy tan radical pues entiendo que añadiendo un método que no existe previamente no se puede generar ninguna confusión. ¿Alguna objeción a este razonamiento?

Un saludo!
__________________
github.com/xgbuils | npm/xgbuils
  #5 (permalink)  
Antiguo 10/07/2014, 10:06
Avatar de stock  
Fecha de Ingreso: junio-2004
Ubicación: Monterrey NL
Mensajes: 2.390
Antigüedad: 17 años, 5 meses
Puntos: 53
Respuesta: Herencia y constructor

La razón que tiene mas peso en mi opinión es compatibilidad, imagínate si todos comenzáramos a agregar funciones al prototype? sería complicado compartir nuestro código, eso sucedía con la famosa librería Prototype, Mootools y otras (hace algunos años), modificaban el prototipo y era imposible usar ambas en un mismo proyecto, jQuery desde un principio soluciono este problema usando su propio namespace.

Mi consejo es que utilices tu propio namespace en lugar de modificar el prototipo.

Saludos
  #6 (permalink)  
Antiguo 10/07/2014, 12:21
 
Fecha de Ingreso: julio-2006
Ubicación: Barcelona
Mensajes: 244
Antigüedad: 15 años, 4 meses
Puntos: 32
Respuesta: Herencia y constructor

Cierto, no lo había pensado así. Ahora mi duda es como se implementa un nuevo namespace. Intentando imitar lo que hace JQuery me ha salido esto:

Código Javascript:
Ver original
  1. function X(f) {
  2.     if( f instanceof Function) {
  3.         return new X.Function(f);
  4.     }
  5. }
  6.  
  7. X.Function = function(f) {
  8.     this.f = f;
  9. }
  10.  
  11. X.Function.prototype.extend = function (base) {
  12.     this.f.prototype = Object.create(base.prototype);
  13.     this.f.prototype.constructor = this.f;
  14. }
  15.  
  16. function B(){
  17.     console.log("B constructor");
  18. }
  19. B.prototype.fbb = function() {}
  20.  
  21. function C(){
  22.     console.log("C constructor");
  23. }
  24.  
  25. X(C).extend(B);
  26. C.prototype.fcc = function() {}
  27.  
  28. var c = new C(); // C constructor : OK
  29. console.log(c instanceof B); // ok
  30. console.log(c instanceof C); // ok
  31. c.constructor(); // C constructor : ok

Primeramente he intentado que la clase X.Function, en vez de tener una propiedad f de la clase Function, fuera una clase extendida de Function. Pero de esta manera no he conseguido hacerlo:
Código Javascript:
Ver original
  1. function X(e){
  2.     if( e instanceof Function) {
  3.         return new X.Function(e);
  4.     }
  5. }
  6.  
  7. X.Function = function() {
  8.     Function.apply(this, arguments);
  9. }
  10. X.Function.prototype = Object.create(Function.prototype);
  11. X.Function.prototype.constructor = X.Function;
  12.  
  13. X.Function.prototype.extend = function (base) {
  14.     this.prototype = Object.create(base.prototype);
  15.     this.prototype.constructor = this;
  16. }

Un saludo!
__________________
github.com/xgbuils | npm/xgbuils

Etiquetas: constructor, herencia
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 16:26.