Scriptia. Javascript y buenas prácticas en español



Scriptia / artículos / De closures y valores «inesperados»: el porqué y una solución

De closures y valores «inesperados»: el porqué y una solución

Saltar a Anotaciones relacionadas

Una closure (cierre) es una función definida dentro del cuerpo de otra. Dentro de ella podemos acceder a las variables definidas dentro de la función padre. Pero en ocasiones, los resultados no son los esperados.

Un ejemplo:

function init() {
    var perricas = "pocas";
    document.body.onclick = function() {
        alert("Mi padre tiene " + perricas + " perricas");
    };
}
init();

Ejecuta este código sobre cualquier página. Al hacer clic sobre cualquier parte del documento se mostrará una alerta con el mensaje «Mi padre tiene pocas perricas».

Veamos un caso en el que el resultado no es el esperado:

function init() {
    var perricas = "pocas";
    document.body.onclick = function() {
        alert("Mi padre tiene " + perricas + " perricas");
    };
    perricas = "muchas";
}
init();

Ahora el mensaje de alerta rezará «Mi padre tiene muchas perricas». Lo cual no está nada mal, puesto que una buena salud económica familiar (intuyo) tiene sus ventajas.

Pero no hablamos de dineros, sino de javascript. Y el hecho de que el padre tenga muchas perricas… parece un error.

¿Dónde está el fallo?

Aquí mismo: el contenido de la variable en la función hija no corresponde al valor de la variable en el momento de la creación de la closure, sino al que ésta –la variable– contiene en el momento en que la función padre finaliza su ejecución.

En otras palabras, la variable perricas contiene el último valor registrado para ella dentro de la función padre.

Una solución quiero

Hela aquí:

function init() {
    var perricas = "pocas";
    (function() {
        var deverdaddelabuena = perricas;
        document.body.onclick = function() {
            alert("Mi padre tiene " + deverdaddelabuena + " perricas");
        };
    })();
    perricas = "muchas";
}
init();

Volvemos a los apuros económicos. En este ejemplo, el manejador del evento onclick no es hijo de la función init, sino de una función anónima que ejecutamos al vuelo (echa un vistazo Funciones anónimas y autoejecutables en javascript si no sabes de qué va la cosa).

Dentro de dicha función anónima, definimos una variable deverdaddelabuena que apunta al valor actual de perricas. El manejador mantiene la referencia al valor de la variable en el momento en que la función anónima finaliza su ejecución, de ahí el regreso a los apuros financieros.

Veamos ahora el mismo problema (y la misma solución) dentro de un bucle.

window.onload = function() {
    var links = document.getElementsByTagName("a");
    for (var el, i = 0, l = links.length; (el = links[i]); i++) {
        el.onclick = function() {
            alert(i);
            return false;
        };
    }
};

Escoge un link al azar, actívalo y… sabrás cuántos enlaces hay en el documento (¿resultado inesperado?). Apliquemos la técnica de la doble closure aquí también:

window.onload = function() {
    var links = document.getElementsByTagName("a");
    for (var el, i = 0, l = links.length; (el = links[i]); i++) {
        (function() {
            var c = i;
            el.onclick = function() {
                alert(c);
                return false;
            };
        })();
    }
};

Esta vez sí. Al activar un enlace, el navegador nos chivará la posición que este ocupa en el documento (el primer enlace ocupa la posición cero).

Este es un tema difícil de entender. Y difícil de explicar. Cualquier aportación para hacer más inteligible la explicación será bien recibida.



Publicidad

Di la tuya

Puedes usar markdown y estas etiquetas HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong> . Por favor, evita el abuso de las mayúsculas y cuida la ortografía.


Acerca de Scriptia

Saltar a la caja de búsqueda

Scriptia forma parte del PDM de Choan C. Gálvez, desarrollador web residente en Barcelona. Scriptia pretende mejorar la calidad de la documentación acerca de javascript disponible en español.