En cursos, videos o blogs nos dicen que var es la manera vieja de declarar una variable, const es una variable que no va a cambiar y let es una variable que cambia y su alcance (scope) es aplicable solo en el bloque donde se declara.

Var vs Const

Para comparar estas 2 formas de declaración de variables vamos a ejecutar javascript en la consola de las devtools del navegador:

var variableRandomOne = 10;
// variableRandomOne 10
// window.variableRandomOne 10

const variableRandomTwo = 20;
// variableRandomTwo 20
// window.variableRandomTwo undefined

Para mostrar el valor de las variables solo necesitamos escribirlas en la consola esto aplica para ambos casos, pero en el caso de var podemos acceder vía el objeto global con window.variableRandomeOne, este nos da el valor de 10. En el caso de la variable declarada con const al usar window.variableRandomTwo el valor es undefined.

Este comportamiento se debe al uso de el Global Enviroment Record de ECMAScript, el cual se utiliza para representar el scope más externo que comparten todos los elementos que se procesan en un scrip de ECMAScript.

Este a su vez consiste en dos environment records:

  • Declarative Enviroment Record se utiliza para definir los enlaces (bindings) de las declaraciones de funciones, de variables y cláusulas catch. En una estructura de datos interna a la que no se puede acceder desde código normal.
  • Object Environment Record es parecido al anterior solo que aquí se utiliza un objeto Javascript como estructura de datos para almacenar esos enlaces definidos (variables, funciones, etc) y asi poder acceder a estas mediante el objeto global window en el navegador.

Entonces var utiliza el Object Enviroment Record, es por eso que lo encontramos en el objeto global window del navegador. Por otro lado, const y let usa el Declarative Environment Record.

Const vs Let

El diccionario javascriptero define a const como la declaración de una variable cuyo valor no se puede cambiar... no se puede cambiar.

Supongamos que necesitamos de un array cuyos valores cambian o se incrementan entonces lo declarariamos de la siguiente manera con let:

let prograLanguages = [];

prograLanguages.push('C');
prograLanguages.push('Java');
prograLanguages.push('Python');
prograLanguages.push('Ruby');

// prograLanguages [ "C", "Java", "Python", "Ruby" ]

Si hacemos lo mismo con const en lugar de let, se supone que según la definición de const, el valor de prograLanguages no deberia cambiar entonces si intentamos agregar elementos al array tendríamos un error al intentar modificarlo.

const prograLanguages = [];

prograLanguages.push('C');
prograLanguages.push('Java');
prograLanguages.push('Python');
prograLanguages.push('Ruby');

// prograLanguages [ "C", "Java", "Python", "Ruby" ]

Y sin embargo funciona, que demonios!!

Para poder entender porque al utilizar un array o un objeto de JS declarado con const es posible modificar su contenido, hay que explicar un poco el modelo de memoria de Javascript.

let numero = 42;

Al ejecutarse el código de arriba lo que va a hacer JS es:

  1. Crear un identificador único para la variable (numero).
  2. Asignarle una dirección de memoria.
  3. Guadar el valor en la dirección asignada.

Ahora que tenemos la variable numero vamos a cambiar su valor:

numero = numero + 1;

En este caso la variable numero va a apuntar a una nueva dirección de memoria y a esa nueva dirección en memoria se le va a asignar el valor nuevo.

En el caso de las variables declaradas con const sucede que no se permite cambiar la dirección de memoria a la que apunta y es por eso que el valor de la variable no cambia.

const numero = 42;
numero = numero + 1;

Ok, pero que hay del caso donde tenemos una variable de tipo const, que contiene un array cuyos elementos y valores son manipulables?

El modelo de memoria en javascript, se constituye de 2 partes:

  • Call Stack almacena los valores primitivos de JS, como cadenas, numeros, valores boleanos, null, undefined, etc.
  • Heap aqui se almacenan los datos no primitivos, desordenados y que pueden crecer de manera dinámica como es el caso de arreglos y objetos.

Ahora ya podemos regresar a nuestro ejemplo:

const prograLanguages = [];

prograLanguages.push('C');
prograLanguages.push('Java');
prograLanguages.push('Python');
prograLanguages.push('Ruby');

// prograLanguages [ "C", "Java", "Python", "Ruby" ]

Si bien no podemos cambiar la dirección de memoria de la variable prograLanguages, siendo su valor otra dirección de memoria en el call stack que apunta al heap aqui ya es posobile modificar el valor o los valores del arreglo.

Esa es la razón lal cual podemos cambiar los valores de un arreglo o un objeto declarado con const.