En este post te voy a comentar las principales diferencias entre estas tres palabras clave en JavaScript y el porque es mala practica seguir usando var.

Compatibilidad con navegadores

Antes que nada, tengo que mencionar que var a diferencia de let y const tiene mayor compatibilidad con navegadores mas antiguos. Lo que le da un punto a favor, pero por lo general deberíamos trabajar con algún transpilador como Babel. el cual nos ayuda con los problemas de retro compatibilidad.Por lo que de todas maneras podríamos evitar usar var en nuestro código.

tipovarletconst
compatilidadnavegadores viejosBABELBABEL

Scope

El alcance de let y const es mas reducido ya que su scope es de bloque (block scope). Por otro lado var tiene un alcance mas amplio, de funcion (function scope). Con esto ya se que no te dije nada; Asi que lo veremos con un ejemplo.

Las variables declaradas con var dentro de una funcion solo se van a poder acceder dentro de la misma.

function iterar() {
  var a = 1 // declaro y asigno un valor a la variable
  for(var a = 0; a < 10; a++) {  //accedo al mimso valor de la variable y la  "inicializo" con valor 0
    //console.log(a)
  }
  
  return a  // devuelve 10, ya que la variable `a` declarada en la primera linea se accedió desde el bloque for y la "piso"

En el código anterior vemos que declaramos la variable usando var dentro de la función. por lo que, a lo largo de la misma podemos acceder a la variable a, esto incluye dentro de un ciclo for. vemos que inicializa el ciclo for con la variable a que es igual a 0. En este punto estamos re asignado el valor, por lo que el resultado final de a es 10.

Por otro lado let y const solo pueden ser accedidas dentro del bloque donde fueron declaradas.

let a = 1 // declaro y asigno un valor a la variable
  for(let a = 11; a < 20; a++) { // inicializo con let pero esta variable solo vive dentro del bloque por lo que no tiene nada que ver con la variable `a` que esta por fuera
    //11,13,14...19
  }
  
  return a  // retorna 1

Usando let vemos que la variable a que se crea en el bloque for no se pisa con el de afuera, ya que la variable vive dentro del bloque.

tipovarletconst
scopefuncionbloquebloque

Re asignación

Como notamos antes var y let nos permite re asignar el valor de la variable.Mientras que con const no se puede re asignar.

Antes que nada quiero diferenciar que es asignar y que es declarar.

Asignar como su nombre indica es asignar el valor de la variable.

let a;

a = 1; //asignación

Declarar es cuando usamos la palabra reservada var , let o const para declarar una variable.Pero no estamos obligados a definir un valor, excepto con const el cual tiene que ser definido y asignado en el momento.

let a; //declaración

Volviendo al tema, let y var nos permiten re asignar el valor de la variable.

let a = 1;
a = 2; //re asignación
var a = 1;
a = 2; //re asignación

OJO, al re asignar el valor no uso la palabra reservada let ya que const y let no permiten re declarar variables. Mientras que var si nos lo permite.

Esto no nos arroja error.

var a = 1;
var a = 2; // re asignación y re declaración

Esto arrojara sintax error.

let a = 1;
let a = 2; // re asignación y re declaración
const a = 1;
const a = 2; // re asignación y re declaración

Lo que si podemos hacer es declarar variables con el mismo nombre pero en otro scope

const nombre = 'nahueldev';

if(nombre === 'nahueldev') {
    const nombre = 'nahueldev2';
    console.log('Estoy en otro scope y uso la variable',nombre) //nahueldev2
}

console.log(nombre) // nahueldev
tipovarletconst
re asignaciónsisino
re declaraciónsinono

Antes de seguir… dijimos anteriormente que podemos declarar sin asignar valor si usamos var o let. Si lo hacemos que valor tendrán por defecto?

var a; //undefined
let b; //undefined
const c; //syntax error
tipovarletconst
declaración sin valor inicialsisino

Propiedades del objeto global window

Cuando declaramos variables con var en el scope global, estas variables se encuentran en el objeto global window.

var a = 1;
console.log(window.a) // 1

Esto no nos pasa con let y const. Otro punto a favor para usar let y const.

Hoisting (elevación de variables)

Lo que hace js al interpretar nuestro codigo es elevar las variables a un nivel superior;Es decir a su scope inmediato.

Supongamos que tenemos el siguiente código;

function filtrarProductoDescuento(productos) {
    var productosConOferta = [];
        for(var i = 0; i < productos.length; i++) {
            var producto = productos[i];
            if(producto.tieneDescuento) {
                var descuento = producto.descuento
                if(descuento > 25) {
                    productosConOferta.push(producto);
                }
            }
        }

    return productosConOferta
}

Lo que hará js es leer o elevar primero las declaraciones de las variables y luego las asignaciones. por lo que lo podemos imaginarlo de la siguiente manera.

function filtrarProductoDescuento(productos) {
    //inicio del scope
    //elevación dee declaraciones
    var productosConOfertal; //undefined
    var i; //undefined
    var producto; //undefined
    var descuento; //undefined

    productosConOferta = [];
        for( i = 0; i < productos.length; i++) {
            producto = productos[i];
            if(producto.tieneDescuento) {
                 descuento = producto.descuento
                if(descuento > 25) {
                    productosConOferta.push(producto);
                }
            }
        }

    return productosConOferta
}

Ojo esto solo lo hace con var con let y const lo hace de una manera distinta.

Es por eso que si primero queremos ver el valor de una variable y luego la declaramos y/o asignamos un valor no nos arroja un error, sino que nos devuelve undefined

console.log(a) //undefined

var a = 10;

Lo que hace en el caso de let y const es elevar la declaración pero no le va a asignar el valor por defecto undefined sino que las va a marcar como no inicializada, es por eso que si hacemos el mismo ejercicio de antes pero con let y const nos arroja un error.(syntax error)

console.log(a) //syntax error

let a = 10;
tipovarletconst
hoistingeleva la declaración y asigna temporalmente undefinedno se tiene acceso al valor hasta su asignaciónno se tiene acceso al valor hasta su asignación