lunes, 26 de mayo de 2014

Javascript, closure, uso this y ámbito variables.

En el post de hoy veremos algunos conceptos bastante básicos pero que es imprescindible desde mi punto de vista dominar si te planteas algún desarrollo serio en javascript. Veremos técnicas “modernas” para encapsular nuestras librerías a la vez que intentaré explicar la diferencia entre ámbito y contexto.

This en javascript representa al contexto donde se invoca al método en el que nos encontramos, por ejemplo si estamos en un ámbito global this contiene información sobre el objeto window pero si hacemos lo mismo dentro de un objeto, this representa el objeto contenedor que llama a la función.

Podrías hacer la prueba y verías que si en ámbito global pones un breakpoint y analizas this, verás que es un objeto Window (navegador) con una serie de atributos. Si haces lo mismo dentro de un objeto, por ejemplo imagina que tienes un objeto persona con una función caminar, si evaluas this dentro de la función caminar verás que se corresponde a la instancia del objeto persona en el que te hallas y los atributos son las variables y métodos que se hayan definido dentro del propio objeto persona. Para llamar a una función situándola en contexto determinado podemos usar el método call o apply que tienen todos los objetos en javascript. Es importante diferenciar contexto y ámbito. Puedes tener 2 tipos de ámbito, global o local mientras que podrías tener infinidad de tipos contextos diferentes (tantos como instancias de objetos tengas).

Respecto al ámbito de las variables podemos definir variables de ámbito global o local. En javascript el ámbito lo marca la función que contiene la declaración de la variable a diferencia de un lenguaje como c# donde el ámbito lo marca el bloque de código. Por ejemplo en c# un If(){} ya tiene su propio ámbito y no podrías usar fuera del bloque del If la variable que has declarado dentro mientras que en javascript si puedes (mejor no lo hagas…). Veamos algún ejemplo en Javascript:
var variableGlobal = "global";
var variableLocal = "local";
algo = true;
function MostrarMensaje() {
   if (algo){
      var variableLocal = "local1";
   }
   alert(variableGlobal + ' ' + variableLocal);
}
function MostrarDeNuevoMensaje(){
   var variableLocal = "local2";
   alert(variableGlobal + ' ' + variableLocal);
}
MostrarMensaje();
MostrarDeNuevoMensaje();
alert(variableGlobal + ' ' + variableLocal);
La función MostrarMensaje sacará un mensaje “global local1, la función MostrarDeNuevoMensaje “global local2” y el alert que está en el contexto global mostrará “global local”. No hay mucho que profundizar simplemente dejar claro que en caso de definir una variable de ámbito local que se llame igual que una global que ya existe dentro de la función donde se ha definido la local, prevalece el valor de la local. No es obligatorio usar var para definir la variable pero sí recomendable sobretodo en ámbito global (…)

Hoy en día está de moda el bundle que es una técnica a través de la cual se fusionan todas las hojas de estilo de un site en un solo documento… hay que ir con cuidado a la hora de desarrollar librerías con las variables globales para evitar que otra librería que a priori no tiene nada que ver modifique el valor de tu variable global. Para evitar esto se suele desarrollar una librería encapsulando el código como si fuese un objeto. Esta técnica es conocida como Closure, y consiste en definir la librería como un objeto singleton. Veamos lo con un ejemplos:
var miLibreria = (function(){
  
})();
Dentro del bloque de código yo definiría los objetos de la librería y luego al final haría un return de este tipo donde devolveré un singleton de mi librería con tantos atributos y funciones como quiera mostrar hacía fuera del objeto.
return { Atributo: _atributo, Atributo2: _atributo2};
Al usar la librería lo haría así:
miLibreria.Atributo 
Veréis que sólo permite acceder a los atributos y métodos que se han definido en el return. De este modo la librería queda protegida y sabemos que nunca se machacarán variables desde fuera de la librería por error. El programador final verá y podrá usar sólo aquellos atributos y funciones que le expongamos en el singleton.

Hasta aquí el post de hoy, recordar que podéis seguir areaTIC en las principales redes sociales. Anímate a participar!

jueves, 15 de mayo de 2014

Javascript, tutorial basado en lenguaje POO

Hace tiempo que tengo ganas de profundizar un poco en javascript, así que hoy me propongo a hacer un artículo rollo tutorial enfocado a gente que domina un lenguaje orientado a objetos como c# o similares y quiere profundizar en js.

Todos en un momento u otro hemos tocado javascript ni que sea para hacer la página del F5 (si aquella que pulsas F5 y sale un alert que te dice por el …. te la hinco) por desgracia con eso no vale para decir que dominas javascript. A día de hoy el lenguaje ha tomado una gran relevancia entre el gremio, y el mundo web en general está evolucionando muy deprisa. Ya no solo se usa javascript para animar algún HTML en cliente o validar datos antes de enviar a servidor… ahora se está empezando a usar en ámbito servidor (por ejemplo node.js) o en cliente pero con un rol mucho más avanzado que el que solíamos otorgar hace unos años (por ejemplo aplicaciones SPA).

Por si no te he convencido a seguir el tutorial en el párrafo anterior, ten en cuenta que compañías como Microsoft en sus últimas versiones de Visual Studio ya dan la opción de desarrollar una aplicación de store para Windows 8 / Windows Phone usando HTML5 y javascript. Aunque mantienen la opción clásica de desarrollar con c#/xaml esto dice mucho sobre la expansión que está teniendo javascript entre los desarrolladores.

Antes de empezar con ejemplos, la primera pega que se encuentra un desarrollador al estar acostumbrado a c# y meterse a aprender javascript es que todo “compila”… (claro es un lenguaje interpretado). En mi caso usaré como IDE Visual Studio 2013 express que ya incorpora intelisense para js con lo que facilita un poco la adaptación y para depurar código uso Chrome.

Bueno me dejo de rollo y empiezo con el tutorial. Lo iré enfocando haciendo símiles entre javascript y un lenguaje POO como c# o java.

Crear una clase


En javascript no tenemos el estamento class pero podemos definir clases de varios modos. Si hacemos uso de this y prototype disponemos de los mecanismos habituales de un lenguaje orientado a objetos como herencia, polimorfismo, etc. Es bastante abierto y hay que ir con cuidado porque dependiendo del modo que decidas usar para definir clases en javascript variará cuantas instancias creas en memoria de un objeto. Recomiendo empaparse bien como funciona Garbage Collector en javascript antes de empezar un desarrollo serio.

En javascript todo son funciones, por tanto una clase en principio será una función:
function Persona(nombre,edad) {
    this.Nombre = nombre;
    this.Edad = edad;
};
La misma definición de la función ya nos hace de constructor y todo lo que encapsulemos dentro de la función precedido de this serán los atributos de nuestra clase.

Instanciar la “clase”:
var persona = new Persona("Carlos", 31);
alert(persona.Nombre);
Como decía hay varios modos de implementar un objeto en javascript, de este modo podríamos tener varias instancias de persona. Otra opción sería crear un singleton (…) que dependiendo del caso podría ser interesante.

Otro tema que no he comentado es que podrías definir atributos (y métodos) como privados usando var en vez de this y luego crear un método público (con this) que haga de getter o setter para asignar valor al atributo lo cual se asemejaría aún más a un lenguaje como C# o java.

Herencia


Se puede implementar la herencia de un objeto usando Prototype. Por ejemplo crearemos una clase Programador que heredará de Persona. Veamos:
function Programador(nombre, edad, lenguaje) {
    this.prototype = Persona.call(this, nombre, edad);
    this.Lenguaje = lenguaje;
};
Veamos como instanciar el objeto:
var programador = new Programador("Carlos", 31, "C#");
alert(programador.Nombre);
Override
Nos puedes interesar como en cualquier lenguaje de programación sobre-escribir un método o atributo de la clase base (modificador override en c#). Lo haríamos del siguiente modo, imaginemos que la clase Persona tiene un método GetEdadEnNumerosRomanos() que por defecto devuelve el valor de la edad en números romanos y queremos que la clase programador lo “pise” y haga lo mismo que el base pero además añada un “-“ al final del resultado. Veamos código:
function Persona(nombre,edad) {
    this.Nombre = nombre;
    this.Edad = edad;
};

Persona.prototype.GetEdadEnNumerosRomanos = function () {
    return "XXXI";
};

function Programador(nombre, edad, lenguaje) {
    this.prototype = Persona.call(this, nombre, edad);
    this.Lenguaje = lenguaje;
};

Programador.prototype.GetEdadEnNumerosRomanos = function () {
    var edadenRomanos = Persona.prototype.GetEdadEnNumerosRomanos.call(this);
    return edadenRomanos += "-";
};
Si os fijáis los métodos los estoy definiendo fuera del ámbito de la “clase”, se podrían definir por ejemplo así:
function Persona(nombre,edad) {
    this.Nombre = nombre;
    this.Edad = edad;
    this.GetEdadEnNumerosRomanos = function () {
        return "XXXI";
    };
};
Según mi punto de vista queda más encapsulado y más mono el problema es que estaríamos creando una función nueva para cada nueva instancia de Persona (raramente te interesará ese comportamiento) mientras que del otro modo la función será única y cada instancia de Persona usará la función (más eficiente). Si nos definimos una instancia de Programador y llamamos a la función GetEdadEnNumerosRomanos nos devolverá “XXXI-“ mientras que si hacemos lo mismo con Persona nos devolverá “XXXI” sin el guión. Con este código podéis hacer la prueba:
var person = new Persona("Carlos", 21);
alert(person.GetEdadEnNumerosRomanos());

var programador = new Programador("Carlos", 31, "C#");
alert(programador.GetEdadEnNumerosRomanos());

Polimorfismo, Boxing-UnBoxing


C# por ejemplo es un lenguaje fuertemente tipado donde para cada variable le especificamos el tipo al declararla. Por ejemplo no podríamos hacer esto.
List<Programador> listaProgramadores = new List<Programador>(){ new Programador(){…}, new Persona(){…});
No compilaría por el segundo elemento de la lista que es de tipo Persona. Si queremos una única lista que almacene las 2 instancias tendríamos que definir una lista de personas en vez de programadores.
List<Persona> listaPersonas = new List<Persona>(){ new Programador(){…}, new Persona(){…});
Esto sí que compilaría, luego si queremos invocar alguna propiedad programador específica tendríamos que hacer un cast.
Programador programador = (Programador)listaPersonas.FistOrDefault();
MessageBox.Show(programador.Lenguaje);
En javascript podríamos asignar objetos de cualquier tipo en la misma lista. Veamos el mismo ejemplo:
var listaPersonas = [new Persona("Carlos", 21), new Programador("Carlos", 31, "C#")];
alert(listaPersonas[0].Nombre + ' ' + listaPersonas[1].Lenguaje);
Esto no quiere decir que el concepto boxing-unboxing no exista javascript, sí que existe lo que no son necesarias conversiones explicitas a la hora de programar.

Interface, Abstract Class


Estos mecanismos en un lenguaje orientado a objetos se usan principalmente para dar comportamiento a los objetos. Es decir, podemos hacer que para que un objeto cumpla una determinada interface tenga implementados una serie de métodos públicos o bien con una clase abstracta podemos obligar también a sus derivadas a implementar ciertos métodos.

Hay modos de definir una clase abstracta en javascript, usaré un ejemplo que he visto por internet y me ha gustado con perros y gatos.
var Animal = Object.subclass(true); // abstracta
Animal.prototype.Dice = function () {
    window.alert(this.Ruido);
};
// definición clases
var Gato = Animal.subclass();
Gato.prototype.Ruido = 'meoooooow';
var Perro = Animal.subclass();
Perro.prototype.Ruido = 'guaoooow';

// uso
var migato = new Cat();
mygato.Dice(); // meooooow!
var migato = new Dog();
miperro.Dice(); // guaoooow!
var mielefante = new Animal(); // error!
La interface como tal no existe pero sí que hay técnicas para saber si un objeto cumple o no determinados comportamientos, intento explicarlo.

Por ejemplo puedes saber si un objeto tiene implementado un método usando este código:
var persona = new Persona("Carlos", 31);
if (typeof (persona.GetEdadEnNumerosRomanos) == "function") {
   alert('el objeto persona contiene este método');
}
Otro modo un poco más elegante sería incorporar una función “can” al prototype de object (todo hereda de object) al que le pasas el nombre de un método y te devuelva si la instancia del objeto que lo invoca implemente el método o no. Al hacerlo en general en Object podremos usarlo en todas nuestras “clases/objetos”.
Object.defineProperty(Object.prototype, 'can', {
    enumerable: false,
    value: function (method) {
        return (typeof this[method] === 'function');
    }
});
Uso:
var persona = new Persona("Carlos", 31);
alert(persona.can("GetEdadEnNumerosRomanos"));
Hasta aquí el primer tutorial de Js espero os resulte interesante. Puedes seguir areaTIC en las principales redes sociales y no te cortes a enviarnos tus críticas, dudas o comentarios. Hasta la próxima!