Las closures las vemos todos los días cuando trabajamos con JavaScript. Las podemos encontrar en todas las librerías y las deberíamos usar en todos nuestros códigos. Esta frase que parece obvia no siempre es así, otras veces si se usan pero no se acaban de entender, aunque en internet hay bastante información sobre el tema he visto interesante escribir un poco sobre ello.
¿Que es una closure?
Es una función que evaluamos en un entorno determinado y que contiene una o más variables de uno o varios entornos, simplificando la definición hablamos de una función que depende de una información no contenida en ella (es decir externa, de otro entorno) y esta función pasa a llamarse closure una vez es evaluada (llamada).
Ejemplo básico
function entorno() {
var i = 1; // declaramos una variable
// declaramos una función que hace algo y retorna un resultado
var incrementa = function () {
i = i * 2;
return i;
}
// retornamos la función anterior
return incrementa;
}
var test = entorno();
/* Ahora en test tengo guardada una función compuesta por una variable i, una variable incrementa y que retorna esta última variable
*/
console.log(test()); // Veremos un 2 en la consola
console.log(test()); // Veremos un 4 en la consola
Básicamente lo que acaba de ocurrir es que en test hemos guardado entorno de manera que entorno es declarado por primera vez y guarda una variable i que vamos actualizando en cada llamada al llamara a incrementa().
Cada llamada a esta función es una closure
function colorea(r,g,b) {
var rgb = 'rgb(' + r +',' + g +',' + b +')';
return function() {
console.log('%c Mensaje de prueba ', 'color: ' + rgb);
};
}
var prueba = colorea(255, 100, 30);
var prueba2 = colorea(100, 100, 255);
prueba();
prueba2();
Lo que vemos en el ejemplo anterior son dos closure que nos van a dar dos resultados distintos aunque están basado en una función.
Los parámetros en una closure
Otra cosa interesante a remarcar es que como hemos podido ver la primera vez que llamo a la closure se ejecuta la función de manera que si le paso un parámetro ya me lo he ‘guardado’ se ve mejor con este ejemplo
function test(param) {
var saluda = 'Hola ';
return function() {
console.log(saluda + param);
};
}
var palabra = 'Quique';
var prueba = test(palabra);
prueba(); // enseña Hola Quique
palabra = 'Carlos';
prueba(); // enseña Hola Quique
Podemos comprobar en este ejemplo que aunque hemos modificado la variable palabra la función test ya había sido ejecutada de manera que en prueba yo tenía algo del estilo:
var prueba = function() { console.log( ‘Hola Quique’) };
De manera que para mi código por mucho que ejecute prueba luego ya le da igual lo que haga con palabra
Caso práctico
En el siguiente ejemplo podemos ver una función anónima en la que tendremos dentro definida otra función, estamos en un caso de closure, podemos ver su comportamiento de una manera bastante clara si ejecutamos este código.
// Defino un objeto
window.MyApp = {
test: 1,
Lorem: {
Ipsum: {
sum: function(a, b) {
return a + b;
}
}
}
};
(function($, global, App, sum){
var num = 1; // nunca podré modificar este valor directamente
App.newSum = function(){
alert(num + App.test) // 1 + x = y
}
alert(sum (5, 10)); // 15 (primero en aparecer)
App.setNum = function(newnum) { // de esta manera modifico la variable num
num = newnum;
}
})(jQuery, window, window.MyApp, window.MyApp.Lorem.Ipsum.sum);
MyApp.newSum(); // 1 + 1 = 2; (segundo)
MyApp.test = 2;
MyApp.newSum(); // 1 + 2 = 3; (tercero)
MyApp.setNum(20);
MyApp.newSum(); // 20 + 2 = 22; (cuarto)