Menu

let, const y var en JavaScript: diferencias y cuándo usar cada uno

Las tres formas de declarar variables en JavaScript: por qué hoy en día usamos const por defecto, let cuando toca, y var prácticamente nunca.

Tres palabras clave, un mismo trabajo

JavaScript tiene tres formas de declarar variables: var, let y const. Las tres asocian un nombre a un valor, pero se diferencian en el ámbito, en si permiten reasignación y en cómo se comportan antes de que se ejecute la declaración. En el código moderno se usa const casi siempre, let cuando el valor necesita cambiar, y var rara vez (o nunca).

En resumen:

index.js
Output
Click Run to see the output here.

El resto de esta página explica por qué esas tres líneas se comportan como lo hacen.

const: la opción por defecto

const crea un enlace que no se puede reasignar. Una vez que escribes const x = 5, ya no puedes volver a escribir x = 6: el motor lanzará un TypeError.

index.js
Output
Click Run to see the output here.

Esa es toda la regla. Como en un programa bien escrito la mayoría de las variables no necesitan reasignarse, const encaja en la gran mayoría de los casos. Empezar siempre por const hace que los sitios donde un valor cambia salten a la vista.

Una confusión habitual: const no es inmutable. Lo que protege es la asignación (el enlace), no el valor en sí. Si el valor es un objeto o un array, su contenido se puede seguir modificando:

index.js
Output
Click Run to see the output here.

const significa "este nombre siempre apunta a este objeto". No significa "este objeto nunca cambia". Si lo que necesitas es congelar el objeto en sí, la herramienta es Object.freeze(user), pero en la práctica casi todo el código se apoya en la convención de que los objetos declarados con const no deberían mutarse.

let: cuándo realmente necesitas reasignar

let se comporta igual que const en todo, salvo en que sí puedes reasignarlo. Úsalo para contadores, acumuladores, variables de bucle y cualquier lugar donde el valor cambie de verdad con el tiempo.

index.js
Output
Click Run to see the output here.

Si te das cuenta de que declaraste algo con let y nunca llegas a reasignarlo, cámbialo a const. De hecho, el linter de casi cualquier proyecto te lo va a marcar solo.

Ámbito de bloque en JavaScript

Tanto let como const tienen ámbito de bloque (block scope). Un bloque es cualquier cosa entre { y }: el cuerpo de un if, de un for, de una función o incluso un bloque suelto { ... }. Una variable declarada dentro de un bloque no existe fuera de él.

index.js
Output
Click Run to see the output here.

Esto es justo lo que buscas: cada variable vive solo donde tiene sentido y se acaban las colisiones accidentales de nombres.

var no funciona así, y esa es la razón principal para evitarlo.

var: ámbito de función y sorpresas inesperadas

var se asocia al ámbito de la función más cercana, no al bloque más cercano. Es decir, un var declarado dentro de un if o un for se "escapa" hacia la función que lo contiene:

index.js
Output
Click Run to see the output here.

Ese scope tan permisivo es el origen de un montón de bugs clásicos de JavaScript. El más típico: bucles donde cada iteración comparte la misma var i y todos los callbacks acaban viendo el valor final.

Además, var te deja volver a declarar el mismo nombre en el mismo ámbito sin rechistar, lo que esconde errores de tipeo:

index.js
Output
Click Run to see the output here.

El código moderno usa let y const casi siempre. var sólo aparece en bases de código heredadas, respuestas viejas de Stack Overflow y scripts que tienen que correr en entornos muy antiguos.

Hoisting y zona muerta temporal en JavaScript

Las tres formas de declarar variables sufren hoisting (el motor las conoce antes de ejecutar el código del bloque), pero su comportamiento antes de llegar a la línea de la declaración no es el mismo.

var se eleva y se inicializa en undefined. Puedes referenciarla antes de la línea del var sin que salte ningún error:

index.js
Output
Click Run to see the output here.

let y const también sufren hoisting, pero no se inicializan. Si intentas acceder a ellas antes de su declaración, se lanza un error. A esa ventana entre la entrada al ámbito y la ejecución de la declaración se le conoce como zona muerta temporal (TDZ):

index.js
Output
Click Run to see the output here.

La TDZ es una característica, no un bug. Convierte el "usado antes de declararse" —que antes se quedaba en un silencioso undefined— en un error bien visible, y eso te ahorra montones de typos y errores de orden.

Usar const en el bucle for...of

Un detalle pequeño pero habitual: los bucles for...of crean un binding nuevo en cada iteración, así que puedes usar const para la variable del bucle aunque "cambie" de una iteración a otra.

index.js
Output
Click Run to see the output here.

Cada iteración crea su propio binding de name: no hay una única variable reasignándose. En cambio, un for (let i = 0; i < n; i++) de toda la vida sigue necesitando let, porque i es un único binding que se va incrementando.

Una regla práctica

A la hora de declarar variables en JavaScript, sigue este orden de preferencia:

  • const por defecto. Si el valor no se va a reasignar, déjalo claro.
  • let cuando el binding realmente tenga que cambiar.
  • var solo si trabajas en un código base que lo exige.

Aplicado con coherencia, esto hace que la intención de cada variable se vea de un vistazo: si se puede reasignar o no, y si su ámbito es este bloque o toda la función.

index.js
Output
Click Run to see the output here.

MAX_RETRIES y users no cambian nunca, así que van con const. successful va creciendo, por eso usamos let. user se vuelve a enlazar en cada iteración, así que también es const. Leyendo de arriba a abajo, se distingue a simple vista qué valores se mueven y cuáles no, sin necesidad de ejecutar el código.

Lo que viene: tipos primitivos

Ya sabes declarar variables, así que toca la siguiente pregunta: ¿qué tipo de valores pueden guardar? JavaScript tiene un conjunto reducido de tipos primitivos —números, strings, booleanos y algunos más—, cada uno con sus peculiaridades. Eso es justo lo que veremos en la siguiente página.

Preguntas frecuentes

¿Cuál es la diferencia entre let, const y var en JavaScript?

const y let tienen ámbito de bloque y se incorporaron en ES2015; var tiene ámbito de función y es anterior. Las variables declaradas con const no se pueden reasignar, las de let sí. Además, var sufre hoisting y se inicializa como undefined, mientras que let y const también se elevan, pero no puedes usarlas hasta que se ejecute su declaración (es la famosa temporal dead zone o zona muerta temporal).

¿const hace que un valor sea inmutable en JavaScript?

No. const solo impide reasignar la variable. Si el valor es un objeto o un array, puedes seguir mutando su contenido sin problema: const user = {}; user.name = 'Ada' funciona perfectamente. Si de verdad necesitas inmutabilidad, tira de Object.freeze o de alguna librería especializada.

¿Debería seguir usando var en JavaScript moderno?

Casi nunca. let y const tienen unas reglas de ámbito mucho más claras y cazan más errores en tiempo de parseo. Solo te vas a cruzar con var en código legacy o en algún script puntual que tenga que correr en entornos sin soporte para ES2015.

Aprende a programar con Coddy

COMENZAR