2012-06-12 19 views
5

Tengo algunos problemas con JavaScript. Tengo el siguiente código:JavaScript: Agregar clase heredada a la matriz no funciona

<html> 
<head> 
<title>Test</title> 
<script type="text/javascript"> 
function Control(){ 
    var name; 

    this.setName = function(newName){ 
     name = newName; 
    }; 

    this.getName = function(){ 
     return name; 
    }; 
} 

function SpecializedControl(){ 
} 
SpecializedControl.prototype = new Control(); 

function Form(){ 
    var formControls = []; 

    this.addControl = function(control){ 
     formControls.push(control); 

     alert(formControls[0].getName()); 
    }; 
} 

var form = new Form(); 

var control1 = new SpecializedControl(); 
control1.setName("Control1"); 
form.addControl(control1); 

var control2 = new SpecializedControl(); 
control2.setName("Control2"); 
form.addControl(control2); 

</script> 
</head> 
<body> 
</body> 
</html> 

SpecializedControl hereda de la clase Control.

La función addControl en la clase Form simplemente agrega el control a una matriz.

El problema es que cuando agrego más de un SpecializedControl, los valores de la matriz son anulados, lo que significa que cuando accedo al primer elemento de la matriz, que debería ser "Control1", obtengo "Control2" . Control1 ya no está en la matriz.

Cuando utilizo la misma función con los objetos de control como parámetros, todo funciona como se esperaba.

¿Alguien sabe por qué sucede esto y qué se puede hacer para corregirlo?

Respuesta

5

Los valores de la matriz no ser manipulables ; el problema es que ambos controles comparten la misma variable name. Como la función Control solo se ejecuta una vez, solo se ha declarado una variable name.

Tiene dos opciones principales para solucionar esto. (1) Haga name una variable de instancia que sea específica para cada control individual (por ejemplo, this._name). (2) Ejecute la función Control desde dentro del constructor SpecializedControl. (En realidad, IMO, para un modelo de herencia bien equilibrado y exhaustivo, debería estar haciendo un poco de estos dos métodos).

Aquí hay tres soluciones de trabajo. Las primeras dos opciones de uso (1) y (2) respectivamente. El tercero combina ambos métodos y es la forma en que lo haría (pero requiere joi).

Opción 1:

function Control(){ 

    this.setName = function(newName){ 
     this._name = newName; 
    }; 

    this.getName = function(){ 
     return this._name; 
    }; 
} 

Opción 2:

function SpecializedControl(){ 
    Control.apply(this, arguments); 
} 

Opción 3:

var Control = joi.Unit.sub(function() { 

    function constructor() { 
     this.base(); 
    } 

    constructor.prototype = { 
     '#name': null, 
     setName: function(name) { 
      this['#name'] = name; 
     }, 
     getName: function() { 
      return this['#name']; 
     } 
    }; 

    return constructor; 

}()); 

var SpecializedControl = Control.sub(function() { 

    function constructor() { 
     this.base(); 
    } 

    return constructor; 

}()); 

var Form = joi.Unit.sub(function() { 

    function constructor() { 
     this.base(); 
     this['#formControls'] = []; 
    } 

    constructor.prototype = { 
     '#formControls': null, 
     addControl: function(control) { 
      this['#formControls'].push(control); 
      alert(this['#formControls'][0].getName()); 
     } 
    }; 

    return constructor; 

}()); 

var form = new Form(); 

var control1 = new SpecializedControl(); 
control1.setName("Control1"); 
form.addControl(control1); 

var control2 = new SpecializedControl(); 
control2.setName("Control2"); 
form.addControl(control2);​ 
+1

recomiendo la segunda opción, llamando al constructor de la superclase en el constructor de la subclase. Parece lo correcto de hacer. La primera opción requiere exponer la variable 'name' y la tercera opción usa una biblioteca adicional que intenta implementar una herencia basada en clases regular como reemplazo de la herencia prototípica de JavaScript. –

+0

joi usa herencia prototípica, herencia no clásica –

+0

Oh, mi mal. Sin embargo, el '#nombre' solo es interno por convención y no impide que acceda desde el exterior. Con cierres, puede tener variables verdaderamente privadas. –

5

Las funciones get/setName obtienen/configuran el valor de la variable name que es local para la función de constructor Control.

La única vez que invocó esa función fue crear una instancia como el objeto prototype de SpecializedControl. Por lo tanto, cada vez que invocó setName desde una instancia SpecializedControl, esa única variable se está actualizando.

Como los métodos get/setName que hacen referencia a esa variable se encuentran en la cadena de prototipos de todas las instancias SpecializedControl, todos observarán el mismo name.


En setName, que debe hacer ...

this.name = newName; 

Y en getName, que debe hacer ...

return this.name; 
Cuestiones relacionadas