JavaScript Closures

Las Closures son funciones que se refieren a variables independientes.

Un ejemplo vale más que mil palabras:

function myFunc() {
  var message = 'Hello';

  function getMessage() {
    console.log(message);
  }

  getMessage();
}

La función myFunc crea una variable local message y una función anidada getMessage. La función anidada getMessage es una Closure y aunque no tiene variables locales es capaz de acceder a las variables de la función padre.

Vamos a hacerlo más interesante:

function myFunc() {
  var message = 'Hello';

  function getMessage() {
    console.log(message);
  }

  return getMessage;
}

var fn = myFunc();
fn(); // Hello

Este código tiene exactamente el mismo efecto que el anterior. La principal ventaja es que estamos exponiendo públicamente la función getMessage, la única en tener acceso a la variable local message de la función myFunc. Esto hace que la variable message no se pueda modificar y cada vez que se quiera acceder a ella se tenga que invocar la función devuelta por myFunc, en este caso la que dejamos en la variable fn.

Funciones y variables privadas

A diferencia de otros lenguajes, JavaScript no ofrece la posibilidad de declarar métodos privados.

Sin embargo gracias a las Closures podemos emular funciones privadas además de poder encapsular el código.

Veamos un ejemplo:

var counter = (function() {
  var value = 0;

  function modify(val) {
    value += val;
  }

  return {
    increment: function() {
      modify(1);
    },
    decrement: function() {
      modify(-1);
    },
    getValue: function() {
        return value;
    }
  }
})();

counter.getValue(); // 0

counter.increment();
counter.getValue(); // 1

counter.decrement();
counter.getValue(); // 0

En este ejemplo tenemos una función counter. Esta función tiene una variable local value privada y método modify privado. Así mismo se están devolviendo 3 métodos increment, decrement y getValue que son públicos.

De esta manera para incrementar el valor del counter tenemos que llamar al método público increment, para disminuir el valor hay que invocar el método decrement y para obtener el valor en curso del counter el método getValue.

Usar Closures de este modo también se conoce como Module Pattern.