Ejemplo práctico de Closure
Abdiel Martinez |¿Qué es un closure y cómo puedes ocuparlos en tu código?
Qué es un closure en JS?
Empecemos por definir que es un closure (algunos los llaman como clausura o cerradura yo prefiero llamarle closure 😅). En pocas palabas un closure es:
Un closure es una función que "recuerda" y mantiene acceso a las variables del contexto donde fue creada
Simple y al grano, es una función dentro de otra. Ahora bien, ¿para qué nos puede servir hacer un closure en nuestro código? La principal ventaja es que nos permite tener variables en la función padre que solo serán accesibles desde la función interna (hija), además de poder acceder también a los parametros de la función padre. Esto nos permite tener un estado privado dentro de nuestra función pero más interesante aún que este sea un estado reusable.
Una parte importante de los closures es que deben ser retornados por la función padre hacia el exterior, a esto se le conoce como función de alto nivel o en inglés High Order Functions, te invito investigar más sobre ello.
Regresando a los closures un ejemplo sencillo sería:
const contador = () => { //funcion padre
let valor = 0; //estado privado y reusable
return ()=>{ //closure o funcion hija
return valor++;
}
}
Ahora para utilizar nuestro closure:
const contar = contador(); //guardamos el closure en la constante contar
console.log(contar()) //0
console.log(contar()) //1
console.log(contar()) //2
Cada vez que llamamos contar() accedemos al closure, se retorna su valor actual y luego suma 1 a la variable valor.
Pruebalo
See the Pen Closure by Abdiel Martinez (@anb98) on CodePen.
A la práctica
Aunque desde que aprendí este concepto me pareció muy interesante, aún no había conseguido encontrar un caso práctico, finalmente encontré uno que podría serle util a más de alguno.
El problema consiste en realizar consultas a una api, en mi caso realtime de firebase, donde cada resultado quede disponible para que en la siguiente vez que se solicite el mismo dato en lugar de volver a llamar a la api, el resultado se devuelva desde el estado local, reduciendo así el tiempo de respuesta.
Mi solución:
import firebase from 'firebase';
import { getDatabase, ref, child, get } from 'firebase/database';
export const searchNode = (node) => {
const data = {}; // estado reusable y privado
return async (value) => { // closure asíncrono
if (!value) // si no se pasa un valor, no hay nada que buscar
return false;
const memoizedValue = data[value];
if (memoizedValue)
return memoizedValue; // si ya existe en el estado local, retornamos el resultado
const db = getDatabase();
const dbRef = ref(db);
try {
const snapshot = await get(child(dbRef, `${node}/${value}`));
if (snapshot.exists()) {
const result = snapshot.val();
result.key = value;
data[value] = result; // guardamos el resultado en el estado local
return result;
}
} catch (error) {
console.error('Error fetching data:', error);
return false;
}
}
}
¿Qué le mejorarías?🤔
Para utilizarlo podría ser:
const buscarAlumno = buscarNodo('alumnos');
const buscarMateria = buscarNodo('materias');
const buscarProfesor = buscarNodo('profesores');
(async ()=>{
// esto es conocido como funcion invocada
// inmediatamente, en ingles:
// Immediately invoked function expression (IIFE)
const alumnoEncontrado = await buscarAlumno( 'idAlumno');
const materiaEncontrada = await buscarMateria( 'idMateria' );
const profesorEncontrado = await buscarProfesor( 'idProfesor' );
})();
Este es mi caso particular, la llamada a firebase podría ser sustituida por cualquier otra api.
¿Qué otra idea se te ocurre para utilizar closures? Compártelo en los comentarios 😊
Articulos relacionados
No más .env perdidos: Una solución self-hosted
Mi experiencia usando Infisical para gestionar variables de entorno: instalación, configuración y uso real en proyectos JavaScript
Descubriendo las Funciones Generadoras en JavaScript
¿Te gustaría saber cómo JavaScript puede pausar y reanudar la ejecución de tu código? Acompáñame a descubrirlo