Closures en javascript

De ChuWiki

Cuando dentro de una función javascript definimos otra función, esta segunda tiene acceso a las variables locales de la primera. Por ejemplo

var a = function () {
   var n=22;
   var b function() {
       console.log(n);
   };
   b();
};

a(); // Saca en console el 22

Si la función a devuelve a la b y la guardamos en una variable, esa función b sigue accediendo a las variables locales que existían cuando fue creada. Por ejemplo

var a = function () {
   var n=22;
   return function() {
       console.log(n);
   };
}

var b = a();  // Ahora b tiene la función interna

b();   // Da 22. 

Esto es el concepto de Closure. Una función va asociada al conjunto de variables que había en su entorno cuando fue creada, mientras exista esa función (en nuestro caso sigue existiendo porque se la hemos pedido a la función a() para guardarla en la variable b), también van a seguir existiendo las variables del entorno donde se creó la función, es decir, las variables locales de la función a.

Un detalle a tener en cuenta es que los parámetros de la función a también son de ese entorno, por lo que la función interna puede acceder a ellos y también se mantendrán mientras exista la función interna

var a = function (n) {
   return function() {
       console.log(n);
   };
}

var b = a(33);

b();  // Saca 33 por pantalla

También debe tenerse en cuenta que estas variables (la n) no dejan de ser variables locales de la función a, por lo que cada vez que llamemos a la función a, tendremos un juego de variables distinto, es decir, habrá varias funciones internas cada una con su juego de variables

var a = function (n) {
   return function() {
       console.log(n);
   };
}

var b = a(33);
var c = a(11)

b();  // Saca 33 por pantalla
c();  // Saca 11 por pantalla

Podemos incluso tener varias funciones internas y todas ellas compartiran el mismo conjunto de variables

var a = function (n) {
   return {
      incrementa:function() {
          console.log(++n);
      },
      decrementa:function() {
         console.log(--n);
      }
   }
}

var b = a(11)

b.incrementa()  // Devuelve 12

b.incrementa()    // Devuelve 13

b.decrementa()    // Devuelve 12

b.decrementa()   // Devuelve 11

Para poder crear una de estas closures ahorrándonos el paso intermedio de asignar la función principal a una variable a y luego llamarla para obtener la función interna, javascript permite hacerlo metiendo toda la definición entre paréntesis, de esta forma javascript además de crear la función, la ejecuta y a la variable a se le asigna lo que devuelva la función. Pondemos detrás entre paréntesis el parámetro que queremos pasarle o () si no lleva parámetros

var b = var b = (function (n) {
   return {
      incrementa:function() {
          console.log(++n);
      },
      decrementa:function() {
         console.log(--n);
      }
   }
})(11)

b.incrementa();  // Devuelve 12
b.decrementa();  // Devuelve 11