Skip to content
En esta página

Cuándo usar var, let o const

Una de las primeras cosas que se enseñan en los cursos de JavaScript es cómo declarar variables. En JavaScript hay tres formas de hacerlo, con var, let o const, y a veces es difícil decidir cuál de las tres usar.

Como regla general, es preferible usar const. En algunos casos es mejor usar let. Pero var... mejor no usarla nunca 👎️

Pero, ¿por qué nunca usar var?

El problema con var

Supongamos que declaro una variable llamada numero que luego la uso en una función que calcula el IVA:

js
var numero = 100

let precioProducto1 = 1000

function calcularIva(precio) {
  return precio * 21 / numero
}

console.log(
  calcularIva(precioProducto1) // 210 👍️
)

Luego, en algún otro lado necesito crear otra variable que contenga un número y como no se me ocurre nada mejor (lo que me suele pasar 🙄️) la llamo también numero:

js
// 200 líneas de JavaScript de por medio

var numero = 0

Y luego, vuelvo a usar la función que calcula el IVA para el precio de otro producto:

js
// Otras 200 líneas de JavaScript mediante

let precioProducto2 = 2000

console.log(
  calcularIva(precioProducto2) // Infinity 
)

El IVA del producto 2 es... infinito 😬️ (porque cualquier número dividido por cero es infinito).

Esto es porque las variables declaradas con var pueden ser re-declaradas con un nuevo valor. En cambio, si las declaramos con let no pueden ser re-declaradas:

js
let numero = 1
let numero = 0 // SyntaxError: Identifier 'numero' has already been declared

Lo que sí se puede hacer con let es re-asignarle un valor (sin re-declararla):

js
let numero = 1
numero = 0

Esto también podría llegar a generar errores como en el ejemplo del IVA, por eso es mejor usar const. Al usar const las variables (o mejor dicho, constantes ) no pueden ser re-asignadas:

js
const numero = 1
numero = 0 // TypeError: Assignment to constant variable.

Pero que no puedan ser re-asignadas no quiere decir que sean inmutables. Por ejemplo, si declaramos un objeto con const cualquiera de sus propiedades internas puede ser mutada:

js
const objeto = { numero: 1 }

objeto.numero = 0

console.log({objeto}) // { objeto: { numero: 0 } }

Lo que no puede ser cambiado es el objeto mismo:

js
const objeto = { numero: 1 }
objeto = { numero: 0 } // TypeError: Assignment to constant variable.

Uno podría decir: bueno, es sólo cuestión de prestar atención a qué nombre le ponemos a las variables y listo. Pero pueden haber otros problemas, por ejemplo al usar var dentro de un ciclo for.

Usando var dentro de un ciclo for

Supongamos que queremos crear una tabla de multiplicar dentro de un array que contiene funciones que ejecutan un console.log con el resultado de cada multiplicación:

js
const tablaDeMultiplicar = []

const cinco = 5

for (let i = 1; i <= 10; i++) {
  let numero = i
  tablaDeMultiplicar[i] = function() {
    console.log(`${cinco} x ${numero} = ${cinco * numero}`)
  }
}

tablaDeMultiplicar.forEach(resultado => resultado())

El resultado es el esperado: 5x1=5, 5x2=10, etc... 👍️

Ahora, ¿qué pasa si en vez de let numero = i ponemos var numero = i?

js
for (let i = 1; i <= 10; i++) {
  var numero = i
  tablaDeMultiplicar[i] = function() {
    console.log(`${cinco} x ${numero} = ${cinco * numero}`)
  }
}

tablaDeMultiplicar.forEach(resultado => resultado())

En lugar de ver la tabla del 5 nos aparece 10 veces lo mismo: 5x10=10 🤨️

Esto es porque en cada ciclo de la iteración la variable declarada con var se pisó a sí misma, con lo cual todas las funciones hacen referencia al último valor de numero, o sea, 10.

Es cierto que hay formas más fáciles de crear una tabla de multiplicar en JavaScript... Pero bueno, es más que nada un ejemplo para mostrar los problemas que puede traer el uso de var.

Uso de var en Vue.js

Tal vez habrán visto que en la documentación oficial de Vue hay ejemplos de código en los que se usa var:

js
var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
})

Sin embargo, para crear una instancia de Vue perfectamente se podría usar usar let o const y funciona exactamente igual:

js
let app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
})

Entonces, ¿por qué el equipo de Vue decidió usar algo tan problemático como var en su documentación? Para ser sincero, no lo sé... 🤷‍♂️️

Mi suposición es que con esto quisieron demostrar que Vue funciona en cualquier browser, incluso en Explorer 😬️, o cualquier versión de Chrome, Safari o Firefox anterior al 2015, año en que let y const fueron incorporadas a JavaScript (o, mejor dicho, a ECMAScript).

Scope de las variables

Cuando una variable es declarada en el ámbito global, es decir, por fuera de cualquier función y por fuera de cualquier bloque de llaves {}, su scope (alcance) siempre es global, es decir, puede ser leída dentro de cualquier bloque o función de ese ámbito:

js
// Esta desestructuración del objeto console
// es sólo para no tener que repetir tantas veces console.log 🥱️
const { log } = console

// Variables declaradas en el ámbito global
const constGlobal = 'const global'
let letGlobal = 'let global'
var varGlobal = 'var global'

// Pueden ser leídas dentro de cualquier función o bloque de ese ámbito
function unaFuncion() {
  if (true) {
    log(constGlobal) // 'const global'
    log(letGlobal) // 'let global'
    log(varGlobal) // 'var global'
  }
}

Y si es declarada dentro de una función su alcance es sólo dentro de esa función, nunca es global, no importa si es declarada con var, let o const:

js
const { log } = console

function unaFuncion() {
  var varLocal = 'var local'
  let letLocal = 'let local'
  const constLocal = 'const local'
}

log(varLocal) // ReferenceError: varLocal is not defined
log(letLocal) // ReferenceError: letLocal is not defined
log(constLocal) // ReferenceError: constLocal is not defined

Existe una excepción a esta regla, y esta es una de las cosas que hacen que los programadores "serios" desprecien a JavaScript. Cuando se usa una variable que nunca fue declarada dentro de una función, en lugar de dar error por no haber sido declarada, automáticamente se transforma en global 🤔️

js
function unaFuncion() {
  numero = 1
}

unaFuncion()

console.log(numero) // 1 🙄️

La única forma de evitar este comportamiento raro es usando 'use strict':

js
'use strict'

function unaFuncion() {
  numero = 1
}

unaFuncion()

console.log(numero) // ReferenceError: x is not defined

Pero por las dudas, siempre hay que estar atentos a que todas las variables que usamos hayan sido previamente declaradas (con let o const, obvio 🙂️).

El scope de las variables en bloques

La única diferencia entre var, let y const en cuanto al scope es que el valor de var puede ser leído por fuera de un bloque de llaves (por ejemplo, un bloque if o for) mientras que let y const, cuando son declaradas dentro de un bloque, sólo tienen alcance dentro de ese bloque:

js
const { log } = console

// Un bloque if
if (true) {
  const constEnBloque = 'const en bloque'
  let letEnBloque = 'let en bloque'
  var varEnBloque = 'var en bloque'
}

log(constEnBloque) // ReferenceError: constEnBloque is not defined
log(letEnBloque) // ReferenceError: constEnBloque is not defined
log(varEnBloque) // 'var en bloque'

Pero que var pueda ser leída por fuera de un bloque no es algo bueno, porque se presta a errores cuando usamos una variable con el mismo nombre, como en los ejemplos del IVA y la tabla de multiplicar.

Cuándo usar let y cuándo usar const

Hay algunas sentencias de JavaScript que sólo funcionan usando let. Por ejemplo, los ciclos for y while:

js
for (const i = 1; i < 10; i++) { // TypeError: Assignment to constant variable.
  console.log(i)
}

const numero = 1
while (numero < 10 ) {
  console.log(numero++) // TypeError: Assignment to constant variable.
}

Y si estamos declarando variables dentro de un scope muy reducido, como una función de 4 o 5 líneas, podemos usar let tranquilamente, porque sería muy raro que pisemos la variable sin darnos cuenta.

Otro caso de uso de let son las variables reactivas en Svelte:

js
<script>
	let framework = 'Svelte'
</script>

{#if framework == 'Svelte'}
<h1>Hola {framework}!</h1>
{/if}

Pero esta es una particularidad de Svelte, en ningún otro framework de frontend puede generarse reactividad usando let.

Por lo tanto, salvo en casos excepcionales, mejor usar const 😎️