Fundamentos de jQuery

2.14. Clausuras

Las clausuras (en inglés closures) son una extensión del concepto de alcance (scope) — funciones que tienen acceso a las variables que están disponibles dentro del ámbito en donde se creó la función. Si este concepto es confuso, no debe preocuparse: se entiende mejor a través de ejemplos.

En el ejemplo 2.47 se muestra la forma en que funciones tienen acceso para cambiar el valor de las variables. El mismo comportamiento sucede en funciones creadas dentro de bucles — la función "observa" el cambio en la variable, incluso después de que la función sea definida, resultando que en todos los clicks aparezca una ventana de alerta mostrando el valor 5.

¿Cómo establecer el valor de i?

/* esto no se comporta como se desea; */
/* cada click mostrará una ventana de alerta con el valor 5 */
for (var i=0; i<5; i++) {
    $('<p>hacer click</p>').appendTo('body').click(function() {
        alert(i);
    });
}

Establecer el valor de i utilizando una clausura

/* solución: "clausurar" el valor de i dentro de createFunction */
var createFunction = function(i) {
    return function() { alert(i); };
};

for (var i=0; i<5; i++) {
    $('<p>hacer click</p>').appendTo('body').click(createFunction(i));
}

Las clausuras también pueden ser utilizadas para resolver problemas con la palabra clave this, la cual es única en cada alcance.

Utilizar una clausura para acceder simultáneamente a instancias de objetos internos y externos.

var outerObj = {
    myName : 'externo',
    outerFunction : function () {

        // provee una referencia al mismo objeto outerObj
        // para utilizar dentro de innerFunction
        var self = this;

        var innerObj = {
            myName : 'interno',
            innerFunction : function () {
                console.log(self.myName, this.myName); // registra 'externo interno'
            }
        };

        innerObj.innerFunction();
        console.log(this.myName); // registra 'externo'
    }
};

outerObj.outerFunction();

Este mecanismo puede ser útil cuando trabaje con funciones de devolución de llamadas (en inglés callbacks). Sin embargo, en estos casos, es preferible que utilice Function.bind ya que evitará cualquier sobrecarga asociada con el alcance (scope).