viernes, 19 de junio de 2009

lo que tengo que decir sobre Internet Explorer

esto es todo lo que tengo que decir sobre Internet Explorer 8
aqui

jueves, 4 de junio de 2009

Funciones lambda o anonimas

Ahora que ya comprendemos el concepto de closures, podremos apreciar con mayor amplitud el verdadero poder de las funciones lambda o anonimas. Pero primero lo primero, porque se llaman lambda?.
Las funciones anonimas en programación deben el nombre de lambda, a la teoría matemática del Calculo Lambda inventada por Alonzo Church y Stephen Kleen (que no es el creador de la botella, ese es Klein) Teoría que sin duda esta fuera del alcance del entendimiento del humano medio, asi que si la comprendes, bien por ti.
Bien, ahora para que son utiles las funciones lambda?, de que sirve no ponerle nombre a una función?. Las utilidaded de las funciones lambda son casi infinitas pero intentaré mostrarles aquí las que yo considero son las más importantes.
Las posibilidad de usar funciones anonimas va de la mano con otros conceptos importantes de Javascript, como :
  • Todo es un objeto: (incluidas las funciones), esto me permite asignar funciones a variables, y hacer referencia a ellas utilizando la variable, además me permite pasar funciones como parametros a otras funciones, y obtener funciones como resultados de la ejecución de una función.
  • Closures: Gracias a las Closures tenemos la ventaja de poder enlazar nuestras funciones con variables de otros entornos de ejecución, algo que veremos es más que util a la hora de trabajar con interfaces web.
  • Objetos dinamicos: A la hora de modificar el comportamiento de un objeto en particular, podemos definir una funcion y asignarla inmediatamente a un método de un objeto, sobreescribiendo su comportamiento inicial, o extendiendo su interfaz para agregar comportamiento nuevo.
bueno ahora un poco de codigo:


//funcion lambda asignada a una variable
var sumar = function (a,b){
return a+b;
}
alert(sumar(1,2));
// es lo mismo que decir
function sumar (a,b){
return a+b;
}


ahora supongamos que tenemos una funcion que busca el más grande de todos los numeros en un array

var masGrande = function (arr){
var mayor=0;
var len = arr.length;
for(var i=0;i<>mayor){
mayor=arr[i];
}
}
return mayor;
}

var intArr = [1,2,3,4,5,6,7,8];
alert(masGrande(intArr));

ahora que sucede si queremos comparar por ejemplo un array de objetos personas, donde cada persona tiene un miembro edad con el valor de su edad. veamos como reescribiriamos la función

var masGrande = function (arrP){
var mayor=0;
var len = arr.length;
for(var i=0;i<>mayor.edad){
mayor=arr[i];
}
}
return mayor;
}
var personasArr = [{edad:2},{edad:2},{edad:2},{edad:2},{edad:2},{edad:2},{edad:2}];
alert(masGrande(personasArr));


Pero este codigo es solamente util para encontrar la mayor "persona", y no sirve para ningun otro tipo de objeto (aunque a decir verdad si los objetos del array poseen un miembro edad es suficiente).
Como podríamos escribir un algoritmo que aisle el comportamiento de buscar un mayor sin importar de los objetos que estemos comparando.
Bueno gracias a las funciones anonimas podemos.

//si analizamos los ejemplos anteriores podemos ver que lo unico que
//cambia es el momento de comparar si un objeto es mayor o no
//entonces que sucede si
var masGrande = function (arr, esMayor){
// en el parametro comparar recibiremos una funcion que compare dos objetos y nos
// pueda decir cual es el mayor.
var mayor=0;
var len = arr.length;
for(var i=0;i< mayor="arr[i];" personasarr =" [{edad:2},{edad:2},{edad:2},{edad:2},{edad:2},{edad:2},{edad:2}];">b.edad){
return true;
}else{
return false;
}
}));

//podemos buscar el mayor número
var intArr = [1,2,3,4,5,6,7,8];
alert(masGrande(intArr,function(a,b){
if(a>b){
return true;
}else{
return false;
}
}));

//podemos buscar el mayor de objetos con estructuras complicadas
var objArr = [{edad:20,fuerza:40},{edad:30,fuerza:50},{edad:10,fuerza:23},{edad:21,fuerza:40}];
alert(masGrande(objArr,function(a,b){
if((50-a.edad)*a.fuerza>(50-b.edad)*b.fuerza){
return true;
}else{
return false;
}
}));


Como vemos hemos logrado aislar el comportamiento de buscar un mayor sin importar los objetos que estemos comparando.

Ahora veamos un ejemplo simple para modificar el comportamiento de un objeto

var perro=function(){};

perro.prototype={
comer: function(){
alert('comiendo con el hocico');
}
};

var persona = new perro;
persona.comer=function(){
alert('comiendo con la boca');
};

es muy sencillo entender la utilidad de este tipo de estructuras luego de observar estos ejemplos
(los ejemplos no han sido probado, si al probarlos encontrases algun error por favor comunicamelo e intenta encontrar la solucion)

Closures

Las closures o cerraduras son un tema bastante explicado en javascript, el problema es que es tan confuso que aún cuando entendamos el concepto dificilmente aprovechamos su potencial en nuestros programas.
Veamos la defininición.
Una Closure es una función que es evaluada en un entorno conteniendo una o más variables dependientes de otro entorno.
Como vemos la definición no hace más que contribuir a la confusión.
Veamoslo así.
En Javascript podemos definir una función en cualquier momento, inclusive dentro de la definición de otra función.
veamos una funcion para encontrar todos los numeros pares entre 2 numeros.


function numerosPares(Desde,Hasta){
function esPar(Num){
if(Num%2==0){
return true;
}else{
return false;
}
//o, lo que es lo mismo
//return !Num%2;
}
var pares = [];
for (var i=Desde;i< Hasta;i++){
if(esPar(i)){
pares.push(i);
}
}
return pares;
}


allí podemos ver como declaramos una función dentro de otra.
Ahora que sabemos esto es mucho más facil comprender que es una closure
vamos a crear una función crearFuncion que, al ejecutarla, devolverá una nueva función sumar que al ser ejecutada actualizará una variable i que fue declarada dentro de la función crearFuncion.

////Closures
function crearFuncion(){
var i=0;
var sumar = function(){
i=i+1;
return i;
};
return sumar;
}


var fsumar = crearFuncion();

alert(fsumar());
alert(fsumar());
alert(fsumar());


ahora podemos ver como al haber declarado la funcion sumar dentro de la función crarFuncion, la función sumar tiene acceso a todas las variables a las que tenía acceso la función crearFuncion, aún despues de que crearFunción finalizó su ejecución. Entonces decimos sumar es una closure ya que poseé acceso a todas las variables de la función donde fué declarada.

Lenguaje dinámico

Bien, javascript es un lenguaje dinámico por que poseé objetos dinámicos. Y... qué es un objeto dinámico?.
Un objeto dinámico es un objeto que puede cambiar la definición de sus miembros en tiempo de ejecución.
cual es la diferencia con un objeto común?
En un lenguaje orientado a objeto y con clases, los objetos son tipicamente estaticos, con lo cual no podemos por ejemplo cambiar la definición de un método en tiempo de ejecución. En cambio en un objeto dinámico si podemos hacer esto.
Es importante comprender que esta caracteristica de javascript afecta profundamente a nuestra forma de programar, ya que nunca podremos estar seguros, a priorí, sobre la definición de los miembros de un objeto que recibamos como parámetro por ejemplo.
Veamos un poco de como utilizar esto en el código.
Supongamos que creamos un objeto iluminador, que posea un método prender y un miembro obj, al ejecutar el método prender, el objeto iluminador se encarga de setear el color de fondo de su objeto obj, a blanco.
(recuerda que puedes ejecutar este código pegandolo en el cuadro de texto en la parte superior derecha de este blog)

/// objetos dinamicos
//definimos el objeto iluminador
var iluminador = function (){
this.obj=null;
}
//definimos el método prender, dentro del prototipo de iluminador
iluminador.prototype.prender = function(){
this.obj.style.backgroundColor = 'white';
}

//Creamos una instancia de iluminador, en la variable i
var i = new iluminador();

//obtenemos una referencia a algun objeto de la página
//en este caso el cuadro de cabecera
var head = document.getElementById('header-wrapper');

//este es nuestro primer caso de objeto dinamico
// hasta ahora no habiamos definido el miembro obj para nuestra instancia i
// ahora colocamos la referencia head en el miembro obj.
i.obj =head;
//podemos ver la definicion de prender
alert(i.prender);
//iluminamos el objeto obj en este caso head
i.prender();


//OBJETO DINÁMICO
//en javascript podemos redefinir un miembro, en este caso un método, en tiempo de
//ejecuccion y de esta forma modificar el comportamiento.
i.prender=function(){
this.obj.style.border = '5px solid green';
}

//ahora el método prender, en lugar de iluminar el objeto obj,
//se encarga de establecer el borde del objeto a 5 pixeles en color verde.
i.prender();

//es importante comprender que el objeto que cambio es el objeto i,
//y no el objeto iluminador, ya que si creamos una nueva instancia del
//objeto iluminador, dentro de la variable i2
var i2 = new iluminador();
i2.obj =head;
//podemos ver que la definicion del miembro prender, continua siendo la del
//objeto iluminador. la razón de esto será mucho más clara cuando
//veamos herencia prototipal
alert(i2.prender);
i2.prender();