Constructores más flexibles

Constructores más flexibles

Las funciones constructoras mostradas hasta ahora no permiten valores cuando crea una instancia. Tal como en Java, puede proveerlas con argumentos para los constructores para iniciar los valores de propiedades para las instancias. La siguiente figura muestra una manera de hacerlo.

Image:hier05.gif
Figura 8.5: Especificando las propiedades en un constructor, take 1

La siguiente tabla muestra las definiciones en Java y JavaScript para estos objetos.

JavaScript Java
function Empleado (nombre, departamento) 
{
  this.nombre = nombre || "";
  this.departamento = departamento || "general";
}
public class Empleado {
   public String nombre;
   public String departamento;
   public Empleado () {
      this("", "general");
   }
   public Empleado (String nombre) {
      this(nombre, "general");
   }
   public Empleado (String nombre, String departamento) {
      this.name = nombre;
      this.dept = departamento;
   }
}
function Tabajador (proyecto) {
   this.proyecto = proyecto || [];
}
Trabajador.prototype = new Empleado;
public class Trabajador extends Empleado {
   public String[] proyectos;
   public Trabajador () {
      this(new String[0]);
   }
   public Trabajador (String[] proyecto) {
      this.proyecto = proyecto;
   }
}
 
function Ingeniero (maquina) {
   this.departamento = "ingeniería";
   this.maquina = maquina || "";
}
Ingeniero.prototype = new Trabajador;
public class Ingeniero extends Trabajador {
   public String maquina;
   public Trabajador () {
      this.departamento = "ingeniería";
      this.maquina = "";
   }
   public Trabajador (String maquina) {
      this.departamento = "ingeniería";
      this.maquina = maquina;
   }
}

Estas definiciones JavaScript utilizan una sintaxis especial para configurar los valores por defecto:

this.nombre = nombre || "";

El operador lógico JavaScript OR (||) evalúa el primer argumento. Si este argumento se convierte a verdadero, el operador lo retorna. En caso contrario, el operador retorna el valor del segundo argumento. Por lo tanto, esta línea de código prueba si el nombre posee un valor útil para la propiedad nombre. Si lo es, configura this.nombre con este valor. En caso contrario, configura this.nombre con una cadena vacía. Este capítulo utiliza esta sintaxis por brevedad; sin embargo, puede parecer ser desconcertante [puzzling] a primera vista. Por favor nótese: Que esta manera puede no trabajar como se espera con argumentos numéricos o lógicos [boolean], tanto como <tt>0</tt> (cero) y <tt>false</tt> ambos causarían que el valor por defecto sea escogido, en este caso necesitará utilizar la siguiente sintaxis muy incómodo, la cual le ofrece el comportamiento deseado con todos los tipos de datos:

this.autorizado = typeof(autorizado) !== 'undefined' ? autorizado : true;

Con estas definiciones, cuando crea una instancia de un objeto, puede especificar los valores para las propiedades localmente definidas. Tal como se muestra en la Figura 8.5, puede utilizar la siguiente sentencia para crear un nuevo Ingeniero:

jane = new Ingeniero("belau");

Las propiedades de Jane son ahora:

jane.nombre == "";
jane.departamento == "ingeniería";
jane.proyecto == [];
jane.maquina == "belau"

Nótese que con estas definiciones no puede especificar el valor inicial para una propiedad heredada tal como el nombre. Si desea especificar un valor inicial para las propiedades heredades en JavaScript, necesita para añadir más código a la función constructora.

Por lo tanto, la función constructora ha creado un objeto general y entonces especifica las propiedades o valores locales para el nuevo objeto. Puede tener el constructor añadido más propiedades directamente invocando la función constructora para un objeto más elevado en la cadena prototipada. La siguiente figura muestra estas nuevas definiciones.

Image:hier06.gif
Figura 8.6 Especificando propiedades en un constructor, take 2

Veamos una de estas definiciones en detalle. Aquí está la nueva definición del constructor Ingeniero:

function Ingeniero (nombre, proyecto, maquina) {
  this.base = Trabajador;
  this.base(nombre, "ingeniería", proyecto);
  this.maquina = maquina || "";
}

Supóngase que crea un nuevo objeto Ingeniero como sigue:

jane = new Ingeniero("Doe, Jane", ["navigador", "javascript"], "belau");

JavaScript sigue los siguientes pasos:

  1. El operador new crea un objeto genérico y configura la propiedad prototipo __proto__ a Ingeniero.prototype.
  2. El operador new pasa el nuevo objeto al constructor Ingeniero como el valor de su palabra clave.
  3. el constructor crea una nueva propiedad llamada base para este objeto y asigna el valor del constructor Trabajador a la propiedad base. Esto hace que del constructor Trabajador un método para el objeto Ingeniero.

    El nombre de la propiedad base no es especial. Puede utilizar cualquier nombre de propiedad legal, base es simplemente evocativa para este propósito.

  4. El constructor invoca al método base, pasándolo como sus argumentos dos de los argumentos pasados al constructor ("Doe, Jane" y ["navigador", "javascript"]) y también la cadena "ingeniería"". Explícitamente utilizando "ingeniería" en el constructor indica que todos los objetos Ingeniero poseen el mismo valor y este valor sobrescribe el valor heredado de Empleado.
  5. Debido a que base es un método de Ingeniero, dentro del cual la invocación a base, JavaScript enlaza esta palabra clave con el objeto creado en el paso 1. Así, la función Trabajador a su vez pasa los argumentos "Doe, Jane" y ["navigator", "javascript"] argumentos de la función constructora Empleado. Hasta retornar desde la función constructora Empleado, la función Trabajador utiliza los argumentos restantes para configurar la propiedad proyecto.
  6. Hasta retornar desde el método base, el constructor Ingeniero inicia la propiedad máquina del objeto con "belau".
  7. Hasta retornar del constructor, JavaScript asigna al nuevo objeto la variable jane.

Puede pensar que, habiendo invocado al constructor Trabajador desde el interior del constructor Ingeniero, tiene que configurar apropiadamente los objetos heredados Ingeniero. Este no es el caso, Invocando al constructor Trabajador asegura que un objeto Ingeniero arranque con las propiedades especificadas en todas las funciones del constructor que son invocadas. Sin embargo, si después añade propiedades a los prototipos Empleado y Trabajador, estos prototipos no son heredados por el objeto Ingeniero. Por ejemplo, asúmase que tiene las siguientes sentencias:

function Ingeniero (nombre, proyecto, maquina) {
  this.base = Trabajador;
  this.base(nombre, "ingeniería", proyecto);
  this.maquina = maquina || "";
}
jane = new Igeniero("Doe, Jane", ["navegador", "javascript"], "belau");
Empleado.prototype.especialidad = "ninguna";

El objeto jane no hereda la propiedad especialidad. Puede mantenerse la necesidad de explícitamente configurar el prototipo para asegura una herencia dinámica. Asúmase en su lugar que tiene la siguiente sentencia:

function Ingeniero (nombre, proyecto, maquina) {
  this.base = Trabajador;
  this.base(nombre, "ingeniería", proyectos);
  this.maquina = maquina || "";
}
Ingeniero.prototype = new Trabajador;
jane = new Trabajador("Doe, Jane", ["navigador", "javascript"], "belau");
Empleado.prototype.especialidad = "ninguna";

Ahora el valor de la especialidad del objeto jane es "ninguna".

<hr>

Otra forma de heredar es mediante el uso de los métodos .call/.apply. Lo siguiente es equivalente:

function Ingeniero (nombre, proyecto, maquina) {
  this.base = Trabajador;
  this.base(name, "ingeniería", proyecto);
  this.maquina = maquina || "";
}
function Ingeniero (nombre, proyecto, maquina) {
  Trabajador.call(this, nombre, "ingeniería", proyecto);
  this.maquina = maquina || "";
}

Utilizar los métodos javascript .call hace que una implementación de limpieza porque ".base" no se necesita nunca más.

Etiquetas y colaboradores del documento

Colaboradores de esta página: DSN XP, Juato, Sheppy, Mgjbot
Última actualización por: Juato,