Volver al inicio

Cierres JS: Entorno Léxico y Ejemplos

Los cierres en JavaScript proporcionan acceso a la función interna para las variables externas después de que la externa termine. El material cubre teoría desde cálculo lambda, prácticas en bucles, emulación OOP y optimización del motor. Ejemplos de código para desarrolladores middle/senior.

Cómo Funcionan los Cierres en JS: Código y Trampas de Bucles
Advertisement 728x90

Cierres en JavaScript: Mecanismo del Entorno Léxico y Aplicaciones Prácticas

Un cierre en JavaScript es una combinación de una función y su entorno léxico, donde una función interna mantiene acceso a variables de un ámbito externo incluso después de que la función externa haya terminado su ejecución. Esto permite la encapsulación de estado y un comportamiento predecible en contextos asíncronos.

El concepto se originó en el cálculo lambda de Alonzo Church. Las funciones de orden superior devuelven o aceptan otras funciones, capturando variables libres—aquellas usadas dentro pero declaradas fuera.

Un ejemplo básico de contador demuestra el principio:

Google AdInline article slot
function counter() {
  let count = 0
  return function(step) {
    count = count + step
    return count
  }
}

const myCounter = counter()
console.log(myCounter(1)) // 1
console.log(myCounter(1)) // 2
console.log(myCounter(1)) // 3

La función interna se cierra sobre count, evitando la recolección de basura. Esta es una referencia viva: los cambios se reflejan en tiempo real.

Cierres como Análogo de POO

Los cierres emulan campos privados y APIs públicas de objetos. Un contador con métodos:

function Counter(initialValue = 0) {
  let count = initialValue
  return {
    increment: function(step = 1) {
      return count += step
    },
    decrement: function(step = 1) {
      return count -= step
    },
    getValue: function() {
      return count
    },
    reset: function() {
      return count = initialValue
    }
  }
}

const myCounter = Counter(10)
console.log(myCounter.getValue()) // 10
console.log(myCounter.increment(5)) // 15

Un equivalente usando clases con campos privados (#count) muestra lógica idéntica. En almacenes Pinia/Vuex, los cierres encapsulan estado reactivo:

Google AdInline article slot
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const initValue = 0
  function increment(step) {
    count.value += step
  }
  return { count, increment }
})

Matices en Bucles e Iteradores

El comportamiento de los cierres en bucles depende del hoisting y el ámbito de bloque.

Con var—una variable compartida para todas las iteraciones:

for (var i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i) // 3, 3, 3
  }, 100)
}

Con let—un entorno léxico separado por iteración:

Google AdInline article slot
for (let i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i) // 0, 1, 2
  }, 100)
}

Iteradores como forEach, map, filter crean cierres automáticamente:

[0, 1, 2].forEach(function(i) {
  setTimeout(function() {
    console.log(i) // 0, 1, 2
  }, 100)
})

Práctica: Callbacks y Eventos

En código asíncrono, los cierres resuelven problemas de contexto.

Ajax con un ID único:

function ajaxRequest(url) {
  let requestId = Math.random().toString(36).substring(2)
  fetch(url).then(data => {
    console.log(`Request ${requestId} completed:`, data)
  }).catch(error => {
    console.log(`Request ${requestId} failed:`, error.message)
  })  
}

Manejadores de eventos:

function clickSetup(elemId, message) {
  const elem = document.getElementById(elemId)
  elem.addEventListener('click', function() {
    console.log(message)
  })
}

Las funciones flecha funcionan de manera idéntica a las regulares.

Optimización y Depuración

Los motores JS (V8) excluyen variables no usadas de los cierres para ahorrar memoria. En DevTools (Scope → Closure), solo las variables relevantes son visibles.

Prácticas clave:

  • Usa let/const en bucles para ámbito de bloque.
  • Prefiere cierres para estado privado sin clases.
  • En callbacks asíncronos, fija el contexto temprano.
  • Monitorea la memoria en cierres de larga duración.

Conclusiones Clave

  • Cierre = función + entorno léxico con referencias vivas a variables.
  • let en bucles crea cierres por iteración, var no.
  • Emula campos privados de POO, usado en almacenes Vuex/Pinia.
  • Optimizado por motores: las variables no usadas se excluyen.
  • Esencial para callbacks asíncronos y eventos.

— Editorial Team

Advertisement 728x90

Leer después