Entendiendo la Mutabilidad y la Re-asignación
Gonzalo Fernández
Posted on June 2, 2024
Buenas, hoy quisiera hablar sobre un tema que puede ser confuso al iniciar en programación, especialmente en lenguajes como Javascript donde la diferencia es tan clara: La Mutabilidad y la Re-asignación.
Al igual que en otros lenguajes, Javascript permite la definición de variables en las cuales almacenar datos. Existen 3 palabras reservadas que nos sirven para definir variables: var
, let
y const
, pero para este artículo, nos concentraremos en estas últimas 2, y ahondaremos en su relación con la mutabilidad y la reasignación.
-
let
: Permite definir una variable cuyo valor puede re-asignarse en cualquier momento. -
const
: Permite definir una variable cuyo valor no puede re-asignarse, esa decir, una constante.
Estas definiciones, si bien son concisas, podrían no bastar para dar cuenta del impacto que tiene el uso de uno versus el otro en Javascript, pues en mi opinión, es necesario hacer énfasis primeramente en los conceptos de re-asignación y mutabilidad que conlleva el uso de una u otra palabra reservada.
Para ello, nos remontaremos a cómo funciona la memoria en un computador: a grandes rasgos, e ignorando cierta cantidad de aspectos fundamentales sobre arquitectura de computadores, es la memoria RAM la que almacena los datos con los que vamos a trabajar. Estos datos tienen direcciones a través de las cuales accedemos a ellos.
Veamos un ejemplo: supongamos que tenemos una memoria RAM de 8 bytes, por lo que si necesitáramos almacenar 1 byte, podríamos hacerlo en cualquiera de los 8 espacios distintos disponibles. Vamos a decir que estos espacios son direcciones de memoria, y los nombraremos del 0 al 7.
Cuando declaramos la primera variable en nuestro código, digamos x = 5
, el computador va a buscar un espacio de memoria disponible en nuestra RAM, digamos que en este caso es el espacio 0, y va a guardar allí el valor 5. Esto significa que la variable x
va a apuntar a la dirección de memoria 0, porque en nuestra memoria RAM hemos guardado el número 5, pero nuestra variable x
no contiene el número 5, sino que contiene la dirección de memoria donde se encuentra el número 5.
Memoria RAM de 8 bytes, con
x
apuntando a la dirección 0 y guardando el número 5.
Ahora bien, tenemos entonces variables que representan direcciones de memoria, y direcciones de memoria en donde se guardan datos. Estos datos pueden ser números, caracteres e incluso punteros. Para entender esto, primero vamos a definir el concepto de puntero:
- Puntero: es un dato que contiene una dirección de memoria de otro dato, por eso se dice que apunta hacia otra dirección de memoria.
Siguiendo con nuestro ejemplo, podemos guardar en la dirección 1 de la memoria un puntero hacia la dirección 2. Por lo tanto, si quisiéramos acceder al dato que se encuentra en la dirección 2, tendríamos que acceder primero a la dirección 1, que nos llevará a la dirección 2.
Supongamos que en la dirección 2 se almacena una Lista de 4 elementos (7, 'a', 'c' y 9)
. Como ya no es un solo dato, vamos a utilizar más espacios de memoria: 4 bytes en total, desde el espacio 2 (el inicio) hasta el espacio 5 (el final). Entonces, resumiendo, en la dirección 0 de nuestra RAM tenemos el número 5, en la dirección 1 tendremos un puntero a la dirección 2, y en la dirección 2 una lista de 4 elementos:
Memoria RAM de 8 bytes, con
x
apuntando a la dirección 0, un puntero en la dirección 1 apuntando a la dirección 2, y 4 elementos correspondientes a la lista que parte en la dirección 2 y termina en la dirección 5.
Teniendo este escenario en mente, vamos a definir los conceptos de re-asignación y mutabilidad. La reasignación es cuando queremos cambiar el valor almacenado en la dirección de memoria que representa nuestra variable. Es decir, la operación x = 10
accedería a la dirección 0 y cambiaría el valor que allí se almacena de 5 a 10, lo que estaría re-asignando a la variable x
. O bien, podríamos re-asignar la dirección de memoria 1 para que deje de almacenar la dirección de memoria 2, y de ahora en adelante guarde un número cualquiera en vez de un puntero.
Por otro lado, diremos que la mutabilidad es la capacidad que tiene una variable de modificar su contenido sin cambiar el valor almacenado en la dirección de memoria que representa. Siguiendo la idea anterior, si tenemos una nueva variable y
que representa la dirección de memoria 1 (que recordemos, almacena un puntero a la dirección de memoria 2, donde hay una lista), y queremos modificar un elemento de esa lista, podemos hacerlo sin cambiar el valor que se encuentra en la dirección de memoria 1. Esto significa que estaríamos mutando la variable y
, ya que vamos a modificar un valor en otra dirección de memoria. Sin embargo, si ahora queremos que la variable y
tenga el valor 3, la estaría re-asignando y no mutando.
En resumen:
- Re-asignación: capacidad de una variable de cambiar el valor almacenado en la dirección de memoria a la que apunta.
- Mutabilidad: capacidad de una variable de modificar su contenido sin cambiar el valor en la dirección de memoria a la que apunta.
Habiendo entendido esto, podemos aterrizar estos conceptos al ecosistema de Javascript, observemos el siguiente ejemplo
const x = 10;
x = 5; // Uncaught TypeError: Assignment to constant variable.
Las variables definidas con const
no se pueden re-asignar, por lo que una vez que le asignamos el valor 10, ya no hay nada más que podamos hacer para modificar ese valor. Lo mismo ocurre con objetos:
const x = { nombre: 'Javascript Chile' };
x.url = 'https://jschile.org/'; // Ningún problema.
x = { url: 'localhost' } ; // Uncaught TypeError:
// Assignment to constant variable.
En este caso, definimos un objeto el cual posteriormente mutamos, añadiéndole la propiedad url
, sin embargo, cuando quisimos asignar un objeto diferente, nos encontramos un error. Esto es porque cuando trabajamos con objetos, lo que se almacena en la dirección de memoria que representa la variable es un puntero, el cual apunta a la dirección de memoria donde se almacena el objeto, y por lo tanto, intentar almacenar otro objeto implicaría cambiar el valor almacenado en la dirección de memoria de x
, cambiando hacia donde apunta el puntero, y por lo tanto intentando re-asignar la variable.
Para finalizar, queda el siguiente ejemplo con let
:
let x = { nombre: 'Javascript Chile' };
x.url = 'https://jschile.org/'; // Ningún problema.
x = { url: 'localhost' } ; // Ningún problema.
Donde ambas operaciones funcionan porque let
permite tanto la re-asignación como la mutabilidad. Dicho esto, vale la pena estudiar más sobre como la mutabilidad impacta en el desarrollo de nuestros productos, y en la forma en la que programamos. A modo de detalle, en este artículo utilizo el concepto re-asignación, porque las memorias RAM siempre tienen un dato asignado, siempre tendrán almacenado un 1 o 0 en sus celdas, por lo que sería erróneo en mi opinión hablar de asignación bajo el nivel de detalle en que se desenvuelve este artículo, más no significa que esté erróneo per sé hablar de asignar una variable.
Espero que se haya entendido bien el concepto con este artículo, y quedo atento a cualquier comentario que puedan tener, por último, quisiera mencionar que este artículo fue extraído de un Apunte de Introducción a Javascript, el cual redacté para mis estudiantes de Desarrollo Web, puedes descargarlo haciendo clic en la imagen:
Nos vemos!
Posted on June 2, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.