jueves, 4 de junio de 2009

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.

13 comentarios:

  1. La mejor explicación de closure que he encontrado, un diez para tí Alejandro. Gracias

    ResponderEliminar
  2. muy buena explicación, se me aclaro el tema con tu explicación.gracias!

    ResponderEliminar
  3. gracias, entendi bien tu explicacion seguire buscando mas informacion acerca de los closures ke tengan buen dia.

    ResponderEliminar
  4. Arre esta muy chida la explicación.

    ResponderEliminar
  5. Porque es necesario hacer esto
    var fsumar = crearFuncion();

    y porque no simplemente llamar a crearFuncion();

    ResponderEliminar
  6. Muchas gracias por tu explicación desde Barcelona

    ResponderEliminar
  7. Eduardo José Villagrán Orellana,

    crearFuncion() te devolverá otra función distinta y para poder ejecutar esa función devuelta(sumar) necesitas guardarla en una variable:

    var fsumar = crearFuncion();

    para después poder hacer esto:

    fsumar();

    No se si estamos de acuerdo?

    =), Saludos!

    ResponderEliminar
  8. Hola, tengo 2 grandes dudas :/

    fsumar() incrementa el valor de i ¿ cierto ?
    entonces funciona algo similar a esto:

    var a = 1;
    while(a < 11) {
    console.log(a);
    a++;
    }

    bueno digamos que si, entonces yo cree una segunda función llamada fsumar2

    var fsumar2 = crearFuncion();

    crearFuncion declara el valor de i igual a 0
    entonces

    ¿por qué fsumar no devolvio 1 como la primera ves que se ejecuto, ya que crearFuncion se ejecuto se definio nuevamente i igual a 0 pero aun asi fsumar seguia conservando el valor que tenia y hasta lo aumento en uno devolviendo 4 ?

    no se si se me entiende lo que trato de decir, espero que si u_ú llevo mucho rato con esta duda :c

    bueno luego me dije: si el comportamiento de fsumar no se vio afectado entonces fsumar2 deberia tambien tener el valor de i igualado a 4 ¿no?
    y ejecute fsumar2 esperando que me devolviera 5 pero NO, SORPRESA !
    me devolvio 1
    y yo quede ._. WTF !?
    porque no se afectan entre ellas si ambas obtienen el valor de la misma variable ( i ) ?

    bueno entonces mi parche temporal, la forma de tranqulizarme a mi mismo explicandome de alguna manera lo que pasa con estas dudas seria que:
    al hacer
    var foo = crearFuncion();

    foo de alguma manera hereda todo lo necesario y se vuelve independiente de crearFuncion, tal como cuando creamos una instancia de objeto con

    var baz = new Algo();

    alguien que me explique pls, estoy desesperado con estas dudas D:
    y si de verdad fuera lo que mi parche temporal dice,
    ¿entonces para que existe new .-.?

    ResponderEliminar
  9. crearFuncion es una factoría de funciones. Si ejecutamos una función, sus variables internas se recrean en cada ejecución y se destruyen al finalizar la misma. Un clojure guarda las referencias a su contexto y por eso tiene acceso a las variables del mismo. Cada vez que ejecutamos una factoría, creas un nuevo contexto para ese clojure

    ResponderEliminar