Command Palette

Search for a command to run...

Variables con let y Block Scope en JavaScript

Descubre cómo let soluciona los problemas de var con block scope, elimina bugs comunes y hace tu código más predecible y seguro.

Lectura: 10 min
Nivel: Principiante

TL;DR - Resumen rápido

  • let fue introducido en ES6 (2015) para reemplazar var y solucionar sus problemas
  • Block scope: las variables let solo existen dentro del bloque {} donde se declararon
  • Temporal Dead Zone (TDZ): no puedes usar una variable let antes de declararla (ReferenceError)
  • No permite re-declaración: intentar declarar let dos veces lanza SyntaxError
  • En bucles, cada iteración tiene su propia copia de la variable let
  • let NO contamina el objeto window cuando se usa en scope global
  • Usa let cuando necesites reasignar el valor, const cuando no lo necesites

¿Qué es let?

let es una forma moderna de declarar variables en JavaScript, introducida en ES6 (2015) como alternativa mejorada a var. Fue diseñado específicamente para solucionar los problemas de var: el confuso function scope, el hoisting problemático, y la re-declaración silenciosa. let introduce block scope, que es el comportamiento que esperan la mayoría de desarrolladores que vienen de otros lenguajes de programación.

La diferencia principal entre let y var es que let respeta los límites de bloques (cualquier par de llaves {}), mientras que var solo respeta límites de funciones. Esto hace que let sea mucho más predecible y seguro de usar. Además, let tiene otras mejoras importantes como la Temporal Dead Zone y la prohibición de re-declaraciones.

Compatibilidad

let está soportado en todos los navegadores modernos desde 2015-2017. Si necesitas soportar Internet Explorer 10 o anterior, herramientas como Babel pueden transpilar tu código de let a var. Sin embargo, en 2025, prácticamente todos los proyectos pueden usar let sin preocupaciones de compatibilidad.

Block Scope Explicado

Block scope significa que una variable solo existe dentro del bloque de código donde fue declarada. Un bloque es cualquier código entre llaves {} - esto incluye if, for, while, funciones, y hasta bloques standalone. Una vez que sales del bloque, la variable ya no existe y no puedes acceder a ella.

block-scope-basico.js
Loading code...

Este ejemplo muestra cómo let respeta los límites del bloque if. La variable insideIf solo existe dentro de las llaves del if. Cuando intentas acceder a ella fuera del bloque, obtienes un ReferenceError. Esto es exactamente el comportamiento que esperarías: las variables declaradas dentro de un bloque permanecen privadas de ese bloque. Este es un cambio fundamental respecto a var, que permitía que las variables escaparan de los bloques.

Bloques Comunes donde let Funciona

let respeta el scope de cualquier tipo de bloque. Esto incluye bloques condicionales (if/else), bucles (for/while), bloques try/catch, y hasta bloques independientes que creas solo para limitar el scope de variables.

bloques-comunes.js
Loading code...

Cada uno de estos bloques crea su propio scope independiente. Las variables declaradas con let dentro de un bloque no son accesibles fuera de él. Nota especialmente el último caso: puedes crear bloques independientes solo con llaves, sin ninguna estructura de control. Esto es útil cuando quieres limitar el scope de variables temporales sin tener que crear una función.

Prevención de Bugs

Block scope previene un bug muy común: declarar una variable dentro de un if o bucle pensando que solo existe ahí, pero que en realidad escapa y causa efectos secundarios en otras partes del código. Con let, si declaras una variable dentro de un bloque, puedes estar 100% seguro de que no afectará código fuera de ese bloque.

Temporal Dead Zone (TDZ)

La Temporal Dead Zone es el período entre el inicio de un bloque y la línea donde se declara la variable let. Durante este tiempo, la variable ya existe técnicamente, pero no puedes acceder a ella. Si intentas usarla, obtienes un ReferenceError. Esto es muy diferente a var, donde puedes usar la variable antes de declararla (obteniendo undefined).

temporal-dead-zone.js
Loading code...

El TDZ existe para hacer el código más predecible. Con var, acceder a una variable antes de declararla daba undefined, lo que podía ocultar bugs. Con let, obtienes un error inmediato que te indica exactamente dónde está el problema. La variable let sí tiene hoisting (se registra al inicio del bloque), pero a diferencia de var, no se inicializa con undefined - simplemente no puedes acceder a ella hasta la línea de declaración.

Error Común: typeof

Incluso usar typeof en una variable dentro de su TDZ lanza ReferenceError. Esto es sorprendente porque normalmente typeof nunca lanza errores (devuelve "undefined" para variables no declaradas). Pero con let en TDZ, sí lanza error. Esto es intencional para forzarte a declarar las variables antes de usarlas de cualquier forma.

No Permite Re-declaración

A diferencia de var, no puedes declarar la misma variable let dos veces en el mismo scope. Si lo intentas, JavaScript lanza un SyntaxError durante la fase de parsing, antes de que el código se ejecute. Esto previene bugs causados por re-declaraciones accidentales, especialmente en archivos grandes donde múltiples desarrolladores trabajan en el mismo código.

no-redeclaracion.js
Loading code...

Este comportamiento protege contra errores difíciles de detectar. Si declaras userName al inicio de una función y 200 líneas después alguien declara let userName nuevamente, obtienes un error inmediato en lugar de un comportamiento inesperado. Sin embargo, nota el último caso: SÍ puedes declarar let con el mismo nombre en bloques diferentes, porque cada bloque es un scope independiente - las dos variables userName son completamente diferentes.

Protección del Desarrollador

Esta restricción es una característica, no un bug. Previene que sobrescribas variables accidentalmente, lo cual era un problema común con var. Los linters como ESLint también detectan este problema, pero tener la protección a nivel del lenguaje es aún mejor porque funciona siempre, incluso sin herramientas adicionales.

let en Bucles: La Solución al Bug Clásico

Una de las mejoras más importantes de let es cómo funciona en bucles. Con var, todas las iteraciones de un bucle compartían la misma variable, causando bugs confusos especialmente con callbacks y setTimeout. Con let, cada iteración del bucle tiene su propia copia independiente de la variable.

let-en-bucles.js
Loading code...

Este ejemplo muestra la diferencia dramática entre var y let en bucles. Con var, solo hay una variable i compartida por todas las iteraciones. Cuando los setTimeout se ejecutan, el bucle ya terminó e i vale 3, por eso imprime "3, 3, 3". Con let, cada iteración crea su propia copia de i en un scope independiente, por eso cada setTimeout captura el valor correcto: 0, 1, 2. Antes de ES6, los desarrolladores usaban patrones complejos (IIFE) para solucionar esto. Ahora, simplemente usa let.

Cómo Funciona Internamente

JavaScript crea un nuevo scope de bloque en cada iteración del bucle for cuando usas let. Es como si cada iteración tuviera su propia caja cerrada con su propia variable i. Las funciones creadas dentro del bucle (como las de setTimeout) capturan la variable de su iteración específica, no una variable compartida.

let vs var: Comparación Lado a Lado

Para entender completamente las ventajas de let, es útil ver una comparación directa con var. Todos los problemas que causaba var están solucionados en let.

let-vs-var.js
Loading code...

Esta comparación muestra las cuatro diferencias principales. Primero, el scope: var escapa de bloques, let no. Segundo, el hoisting: var permite acceso antes de declaración (undefined), let lanza error (TDZ). Tercero, re-declaración: var lo permite silenciosamente, let lanza error. Cuarto, window: var contamina el objeto global, let no. En todos los casos, el comportamiento de let es más seguro y predecible.

Cuándo Usar let

let se usa cuando necesitas declarar una variable cuyo valor va a cambiar durante la ejecución del programa. La pregunta clave es: ¿necesitas reasignar esta variable? Si la respuesta es sí, usa let. Si no, usa const. Esta es la regla simple que debes seguir en JavaScript moderno.

cuando-usar-let.js
Loading code...

Los casos de uso típicos para let incluyen: contadores en bucles, acumuladores que se van sumando, variables que cambian en condicionales, y cualquier valor que necesites actualizar durante la ejecución. En todos estos casos, necesitas la capacidad de reasignar la variable. Por el contrario, si declaras una variable con un valor que no cambiará (como una configuración, una referencia a un objeto, o un resultado calculado), usa const.

Regla de Oro

Usa const por defecto para todas las variables. Solo cambia a let cuando descubras que necesitas reasignar el valor. Esta práctica hace tu código más fácil de entender porque al ver const sabes que el valor nunca cambia, mientras que let te indica que debes prestar atención a cómo cambia esa variable a lo largo del código.

Errores Comunes con let

Aunque let es más seguro que var, todavía hay errores comunes que los desarrolladores cometen, especialmente quienes están aprendiendo JavaScript o vienen de código legacy con var.

errores-comunes.js
Loading code...

El primer error es intentar usar let antes de declararla, causado por confundir el comportamiento de var. El segundo es intentar re-declarar, un hábito de código con var. El tercero es asumir que let en un bloque es accesible fuera de él. El cuarto es un caso especial: usar let en un bucle dentro de una función asíncrona, donde aunque let crea scopes separados, el valor puede cambiar antes de que el callback se ejecute si no tienes cuidado con el timing.

Resumen: let y Block Scope

Ventajas de let:

  • Block scope - variables limitadas al bloque donde se declaran
  • Temporal Dead Zone - error si usas la variable antes de declararla
  • No permite re-declaración - previene sobrescribir variables accidentalmente
  • Funciona correctamente en bucles - cada iteración tiene su propia copia
  • No contamina window - no crea propiedades globales

Cuándo usar let:

  • Cuando necesites reasignar el valor de la variable
  • Contadores en bucles (for, while)
  • Variables que cambian en condicionales
  • Acumuladores que se van sumando o modificando
  • Regla: usa const por defecto, let solo si necesitas reasignar