Desarrollar eficazmente con orientación a objetos
Primera aproximación
1. Repaso
Antes de abordar en concreto el desarrollo orientado a objetos en JavaScript, vamos a repasar algunos conceptos básicos sobre este modo de desarrollo. En primer lugar, hay que entender bien que este tipo de desarrollo se concibió con el objetivo de mejorar la calidad del desarrollo, distinguiendo varios niveles de diseño. El primer nivel consiste en establecer un plan de fabricación y el último permite obtener un ensamblaje de objetos que presta el servicio deseado. Por otra parte, algunos métodos de análisis y diseño han intentado seguir este modelo para garantizar una transición más flexible en el desarrollo, desde la modelización de la realidad hasta la etapa de fabricación.
a. Clase
Un objeto se construye generalmente a partir de una clase. Esta clase actúa como una fábrica de objetos. Posee un plan de fabricación y puede suministrar objetos bajo demanda.
En los planes de fabricación, tenemos propiedades (o atributos) que almacenan información específica de cada objeto y métodos que permiten interactuar con dichos objetos.
Una propiedad es, en realidad, una variable cuyo contexto de uso se limita a un objeto en particular. En cierto modo, solo existe dentro del objeto, lo que le confiere a este último un estado.
Un método de un objeto también es una función de JavaScript, pero solo existe en el contexto de ese objeto y tiene acceso a sus propiedades, por lo que puede influir en su estado.
Si hacemos una analogía con los objetos de nuestro entorno, podemos tomar como ejemplo un teléfono móvil. Sus propiedades consisten en su configuración y en la información que hemos almacenado en él; se observa claramente que están vinculadas solo a un dispositivo. Los métodos son el conjunto de acciones disponibles en el móvil, como encenderlo, ajustar el volumen o realizar una llamada. Como están presentes en todos los dispositivos, una clase Móvil debería incluirlos.
Un objeto puede estar compuesto por otros objetos; es un ensamblaje de objetos. Un teléfono móvil tiene una batería, una placa base, una pantalla, etc. La placa base puede dividirse a su vez en placa de cobre, transistores, resistencias, etc. Una propiedad de un objeto no es, en realidad...
Contexto de ejecución
1. this
En JavaScript, this no se refiere únicamente al objeto instanciado, sino que, en realidad, se refiere al objeto que se está utilizando en ese momento. Esto significa que el intérprete de JavaScript evalúa this al llamar a un método; es un argumento adicional que se añade automáticamente.
En otras palabras, cuando se hace referencia a this, nunca se tiene la certeza de que vaya a referirse a la instancia correcta. Esta particularidad resulta bastante desconcertante para un desarrollador orientado a objetos «clásico», pero en realidad ofrece un gran potencial, como veremos a continuación.
Ejemplo
function Persona(apellido, nombre) {
this.apellido = apellido;
this.nombre = nombre;
this.hola = function() {
alert( "hola " + this.nombre);
};
}
function Perro( nombre ) {
this.nombre = nombre;
}
const p = new Persona( "Brines", "Alejandro" );
const c = new Perro( "Toby" );
c.hola = p.hola;
c.hola();
En el ejemplo, tenemos dos clases: Persona y Perro. Estas clases no tienen ninguna relación entre sí en un principio. Asociamos a la clase Perro el método hola procedente de la clase Persona y, a continuación, ejecutamos este método a través de una instancia. Obtenemos entonces el mensaje «hola Toby».
this representa la instancia sobre la que se realiza una llamada al método.
Esto se puede representar así: miInstancia.miMetodo( ... )
En realidad, el comportamiento interno se representa de esta manera:
this = miInstancia
miMetodo( this, ... )
Ahora, imaginemos que tenemos que pasar una referencia a una función de nuestro objeto. Como recordatorio, JavaScript es un lenguaje que, en su origen, fue diseñado para funcionar con una página HTML. En una página HTML, tenemos todo tipo de eventos que estarán vinculados a las interacciones directas o indirectas del usuario y que requerirán un tratamiento en forma de llamada a un método. Este método puede proceder perfectamente de uno de nuestros objetos.
Ejemplo
setTimeout( function() { alert(...Clases predefinidas
A continuación, vamos a presentar algunas clases de uso común. El objetivo no es ofrecer una descripción exhaustiva de las propiedades y métodos de cada clase, sino centrarnos en los más útiles. Para obtener una visión más completa, puede consultar los enlaces que se incluyen al final del libro.
1. Object
Todos los objetos creados en JavaScript comparten las propiedades y los métodos de la clase Object.
La propiedad principal es prototype, que analizaremos más adelante y que tiene la ventaja de dar acceso a propiedades y métodos presentes una sola vez para todas las instancias.
Ejemplo
function Persona( apellido, nombre ) {
this.apellido = apellido;
this.nombre = nombre;
}
const p1 = new Persona( "Brines", "Alejandro" );
const p2 = new Persona( "García", "Juan" );
Persona.prototype.hola = function() {
alert( "hola " + this.nombre );
};
p1.hola();
p2.hola();
En este ejemplo, añadimos un método hola a la clase Persona y lo compartimos con todas las instancias. Prueba de ello es que lo hemos añadido después de la creación de los objetos y, sin embargo, está disponible con p1 y p2.
El método toString también está presente en la clase Object, que es la clase padre por defecto, y sirve para ofrecer una representación más legible del objeto.
Ejemplo
function Persona( apellido, nombre ) {
this.apellido = apellido;
this.nombre = nombre;
}
const p3 = new Persona( "Brines", "Alejandro" );
alert( p3 );
Obtenemos el resultado [object object], que es poco legible y que simplemente significa que nuestro objeto está compuesto a su vez por dos objetos (las cadenas de caracteres «apellido» y «nombre»).
El método alert utiliza en realidad el método toString, presente por defecto en la clase Object. Para mejorar la visualización, vamos a ampliar un poco nuestra clase Persona.
function Persona2( apellido, nombre ) {
this.apellido = apellido;
this.nombre = nombre;
this.toString...Clases
1. Creación
a. Constructor
Desde el estándar ECMAScript 6 (ES6), y con el fin de evitar la confusión entre «función constructora» y «función clásica», JavaScript ha introducido el concepto de constructor, tal y como existe en otros lenguajes. Esto significa que una clase también se puede representar mediante la palabra clave class. A continuación, se utiliza la palabra clave constructor dentro de la clase.
He aquí un ejemplo con una clase «Pez»:
class Pez {
constructor(especie, color) {
this.especie = especie;
this.color = color;
}
getEspecie() {
return this.especie;
}
getColor() {
return this.color;
}
}
const pez = new Pez( "pez gato", "negro" );
alert( `Nuestro ${pez.getEspecie()} es de color
${pez.getColor()}` );
Por convención, hemos puesto un nombre de clase que empieza por mayúscula. Asimismo, los métodos de las clases empiezan por minúscula. No es necesario declarar los atributos/propiedades de la clase, ya que se definen en el momento de usarlos, tan pronto como se utiliza la instrucción this.atributo = valor, especialmente en el constructor.
Hemos definido dos atributos, especie y color, en el constructor. Para leer estos atributos, hemos añadido los métodos getEspecie y getColor. Empezar por «get» es una convención bastante habitual para indicar una operación de lectura; del mismo modo, para una operación de escritura, tendremos un método que empieza por «set».
La creación de una instancia siempre se realiza mediante el operador new con los parámetros del constructor. A continuación, mostramos la información de nuestro objeto mediante los getters (término que designa a todos los métodos que comienzan por get).
Cabe señalar que, por defecto, todos los atributos son directamente...