Terminologia de programación orientada a Javascript

Intro

Estoy muy contento y con muchas ganas de escribir este post, es muy importante que entiendas los conceptos clave utilizados en Javascript que te permitiran convertirte en un mejor programador, ingeniero, etc etc.

La inspiración de este post se debe a que ahora me quedan bastante claros estos conceptos, y me han hecho mejor programador. Este post esta dirigido a esas personas que "quieren" tanto a Javascript como yo, y que quieren sentirse bien a la hora de explicar a otra persona con conceptos claros y consisos o de entender una explicación sin avergonzarnos de no entender una palabra.

Terminología

Clase

La clase, un palabra muy interesante a la hora de hablar de Javascript ya que (por lo menos en ES5) las clases no eran necesariamente clases, sino objetos o funciones "padre" que algun momento heredarian sus propiedades a sus hijos y futuros hijos.

Podemos decir que una clase define las características de un Objeto, para hacerlo mas practico veamos un ejemplo y entendamoslo.

En el siguiente ejemplo una clase Persona, la misma que sera utilizada para heredar sus propiedades a otras "personas" ya que que todas las personas tienen en comun distintos atributos como: el de nombre, la edad, el usuario de twitter y como ejemplo de mostrar que son los metodos, crearemos uno que al invocarlo la persona gritara su nombre.

function Persona(){  
   this.nombre = '';
   this.edad = 0;
   this.twitter = '@';
   this.gritar = function(){
     alert('Hola mi nombre es ' + this.nombre + '!');
   }
}
Constructor

Es un método llamado en el momento de la creación de instancias (objetos hijos).

var rene = new Persona();  

El constructor crea la instancia y le añade las propiedades de la "clase" al nuevo objeto, podemos decir que el constructor "construye".

Objeto

Los objetos son nada mas que simple instancias de una Clase, como creamos estas instancias?, de esta manera:

var rene = new Persona();  

por lo tanto la variable rene contiene esto:

Persona {nombre: "", edad: 0, twitter: "@", gritar: function}  
Propiedad

Las propiedades son aquellas características del Objeto, en este ejemplo tenemos 3 distintas propiedades la edad, el nombre y el twitter. Hablemos de la edad, la misma es heredada con un valor de 0, ¿Como podemos modificar la edad de 0 con la edad real de la persona?, por ejemplo, rene tiene 24 años, entonces asignamos el valor de la siguiente manera.

rene.edad = 24;  

Debido a que la variable rene es un objeto o instancia de la clase persona, la misma tendra las propiedades que fueron heredas de la clase, y para modificarse simplemente debemos referinos a aquella propiedad del objeto "rene" que queramos modificar. Antes de mostrar cual seria el resultado, cambiemos el valor del nombre y su usuario en twitter.

rene.twitter = '@chitopolo';  
rene.nombre = 'Rene';  

Una vez modificado veremos lo siguiente al typear rene enter, veremos

Persona {nombre: "Rene", edad: 24, twitter: "@chitopolo", gritar:function}  
Método

El metodo es una propiedad que contiene en vez de un solo valor, una funcion la cual para ser invocada se debe agregar el () al final logrando de esta manera algo como rene.gritar() para ejecutarla, caso contrario, el resultado sera la funcion como tal sin ser invocada el resultado seria este

> rene.gritar // enter
> function(){
     alert('Hola mi nombre es ' + this.nombre);
   }

versus lo que realmente queremos.

> rene.gritar()

El metodo invocado abrira una alerta alert('Hola mi nombre es ' + this.nombre);

en este caso this.nombre sera reemplazado por rene.nombre el cual tiene un valor de 'rene' por lo tanto el resultado sera:

________________________

Hola mi nombre es rene  
________________________
Antes de continuar hablemos de 'this'

Por que this.nombre equivale a 'rene', en ese caso no deberia ser rene.nombre?, ¿Como sabe 'this' que valor mostrar?, ¿Que pasa si tenemos mas instancias, a que se refirira 'this'?

Esto debido a que this esta siendo ejecuntado dentro el contexto de rene, para identificar el contexto de 'this' debemos mirar a la izquierda del punto que invoco al metodo, es decir, el metodo fue invocado rene.gritar() por lo tanto a la izquierda del punto tenemos a rene con sus propiedades, por lo tanto this.nombre dentro el contexto de rene, tiene un valor de 'rene' al igual que rene.nombre.

   this.gritar = function(){
     alert('Hola mi nombre es ' + this.nombre);
   }
Herencia

La herencia es una manera de crear una clase como una versión especializada de una o más clases (JavaScript sólo permite herencia simple). La clase especializada comúnmente se llama hija o secundaria, y la otra clase se le llama padre o primaria. En JavaScript la herencia se logra mediante la asignación de una instancia de la clase primaria a la clase secundaria, y luego se hace la especialización.

En otras palabras podemos representar esto como una clase de la cual descienden distintas clases que requieren de atributos de la clase padre, pongamos un nuevo ejemplo.

En un colegio existen Estudiantes, Docentes y Administrativos. Los estudiantes que cuentan con datos como fecha de inscripción, grado, datos de contacto en caso de emergencia, los Docentes con distintos datos como sueldo, fecha de contratación, entre otros. Los Administrativos los cuales cuentan con información como usuario, contraseña, cargo, entre otros.

Ahora que mencionamos estas distintas propiedades que dichas entidades no comparten, hablemos de lo que si comparten:

  • Nombre
  • Apellido
  • Fecha de Nacimiento
  • Telefono
  • Y otros...

Imaginate la tarea de tener que escribir las propiedades de un estudiante, luego las del docente y luego las de administrativos de esta forma.

Estudiante
function Estudiante(){  
    this.nombre = '';
    this.apellido = '';
    this.fechaDeNacimiento = DD/MM/AAAA;
    this.telefono = '';

    this.fechaDeInscripcion = DD/MM/AAAA;
    this.grado = 0;
    this.datoDeContacto = '';
}
Docente
function Docente(){  
    this.nombre = '';
    this.apellido = '';
    this.fechaDeNacimiento = DD/MM/AAAA;
    this.telefono = '';

    this.fechaDeContratacion = DD/MM/AAAA;
    this.sueldo = 0;

}
Administrativo
function Administrativo(){  
    this.nombre = '';
    this.apellido = '';
    this.fechaDeNacimiento = DD/MM/AAAA;
    this.telefono = '';

    this.cargo = '';
    this.usuario = '' ; 
    this.contrasena = '';
}

fijemonos la cantidad de veces que repetimos estas lineas de codigo:

    this.nombre = '';
    this.apellido = '';
    this.fechaDeNacimiento = DD/MM/AAAA;
    this.telefono = '';

Si bien estas propiedades son comunes para todas las clases creadas podriamos crear una clase que tenga las propiedades basicas (las que repetimos en todo momento) para luego poder crear clases independientes que contengan los valores no comunes.

Empecemos creando la clase padre Persona.

function Persona(){  
    this.nombre = '';
    this.apellido = '';
    this.fechaDeNacimiento = DD/MM/AAAA;
    this.telefono = '';
}

Ahora creemos la clase estudiante.

var estudiante = new Persona()  
estudiante.fechaDeInscripcion = DD/MM/AAAA;  
estudiante.grado = 0;  
estudiante.datoDeContacto = '';  

imprimimos estudiante, y tendriamos toda su información completa, es decir, lo heredado mas los parametros especificos de esta instancia. Ahora creemos a la instancia Docente:

var docente = new Persona();  
docente.fechaDeContratacion = DD/MM/AAAA;  
docente.sueldo = 0;

y ahora Administrativos:

var administrativos = new Persona()  
administrativos.cargo = '';  
administrativos.usuario = '' ;  
administrativos.contrasena = '';  

Entonces, te das cuenta cuantas lineas de codigo nos hemos ahorrado?, no solo por ahorrarnos, si no que es mas profesional desde todo punto de vista, el manejar de forma dinamica todas las instancias u objetos heredados.

Encapsulamiento

Una Clase sólo define las características del Objeto, un Método sólo define cómo se ejecuta el Método.

En el ejemplo anterior, Student no tiene que saber cómo se aplica el método walk() de la clase Person, pero, sin embargo, puede utilizar ese método. La clase Student no tiene que definir explícitamente ese método, a menos que queramos cambiarlo. Esto se denomina la encapsulación, por medio de la cual cada clase hereda los métodos de su elemento primario y sólo tiene que definir las cosas que desea cambiar.

Abstracción

La conjunción de herencia compleja, métodos, propiedades que un objeto debe ser capaz de simular en un modelo de la realidad.

Un mecanismo que permite modelar la parte actual del problema de trabajo. Esto se puede lograr por herencia (especialización) o por composición. JavaScript logra la especialización por herencia y por composición al permitir que las instancias de clases sean los valores de los atributos de otros objetos.

La clase Function de JavaScript hereda de la clase de Object (esto demuestra la especialización del modelo) y la propiedad Function.prototype es un ejemplo de Objeto (esto demuestra la composición)

Polimorfismo

Diferentes Clases podrían definir el mismo método o propiedad.

Al igual que todos los métodos y propiedades están definidas dentro de la propiedad prototipo, las diferentes clases pueden definir métodos con el mismo nombre. Los métodos están en el ámbito de la clase en que están definidos. Esto sólo es verdadero cuando las dos clases no tienen una relación primario-secundario (cuando uno no hereda del otro en una cadena de herencia).

Programación Orientada a Objetos

Al desarrollar una aplicación en cualquier lenguaje, tu código debe ser dividido en diferentes partes, donde cada parte es responsable de un área diferente en tu programa. Esto quiere decir que la lógica para cada tarea que tu programa realiza debe evitar interferir con otras tareas.

Por ejemplo, el código que permite la comunicación con la base de datos mediante el internet no debería mezclarse con el código que muestra los resultados al usuario. Por lo contrario, tu deberias tener una sección de código que hace la interacción con la base de datos y otra que muestra los datos. Cuando estas dos secciones necesitan comunicarse, estas deberian hacerlo mediante interfaces bien definidas e independientes.

Esto permitirá que tu codigo se vuelva más sencillo de escribir, de mantener y de debuggear. Esto permitirá modularidad en tu aplicación, esto como consecuencia traera consigo la facilidad de permitirte editar, mejorar y/o reemplazar el codigo de la seccion que necesites editar evitando afectar el resto de la aplicación.

Ademas de separar la lógica basada en su funcionalidad, los datos de tu aplicacion tambien deberian ser separados. Para continuar con el ejemplo, información que deba ser mostrada (la tipografía, el color, la posicion en la pantalla) no deberían ser modificados por el código que es responsable de comunicarse con la base de datos y viceversa. Además, la lógica debería ser capaz de trabajar asumiendo que la información que esta funcionando no será modificada por otras partes de la aplicación.

La programación orientada a objetos exige esta separacion mediante el uso del concepto de "objetos".

Objetos

El objeto es un conjunto de datos que estan relacionados mediante codigo que actúa sobre esos mismos datos, los objetos pueden comunicarse con otros para compartirlos entre ellos mismos.

Esta forma de ocultar datos de otros objetos es llamado "encapsulación", y permite garantizar que la información del objeto puede ser modificado por las propias funciones de ese objeto.

Varias copias del objeto estan permitidas de existir al mismo tiempo. Cada copia del objeto es conocida como "instancia". La plantilla de donde cada instancia es creada se llama "clase". Cuando se escribe código utilizando el paradigma de programación orientada a objetos, escribes clases, y tu codigo crea una o mas instancias de cada clase.

Los datos que pertenecen al objeto es llamado variable de instancia. Una función que pertenece a un objeto es llamado Método.

En la mayoría de los lenguajes orientados a objetos, es también posible para un método de pertenecer a una clase, no solamente a la instancia de una clase.

Herencia

Los lenguajes orientados a objetos permiten definir una clase como subclase por alguna otra. Las subclases son identicas a sus clases, pero añaden métodos adicionales y variables de instancia.

Las subclases permiten crear versiones más específicas de la clase. Por ejemplo, podrías definir una clase Server, que manejara tareas como aceptar la conexión de la red, ademas de crear de forma separada subclases FTPServer y un HTTPServer subclases de la clase Server, que son más específicos a distintas funcionalidades.

Dudas, preguntas y comentarios a @chitopolo, sigueme en twitter! ;)

Referencias:
Developer Mozilla y Learning Cocoa with Objective-C - O'Reilly - 4 edition.

Rene J Polo

Read more posts by this author.

Cochabamba - Bolivia

Subscribe to Chito Tech Tips

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!