¿Qué hay tras las variables en JavaScript?

Share on facebook
Share on twitter
Share on linkedin

¿Alguna vez te has topado bugs extraños, con objetos o arreglos mientras programabas en JavaScript? Por ejemplo un arreglo que debería estar lleno, pero le faltaban elementos y tú juras que están ahí. Yo sí, me ha pasado tanto en NodeJS como en VueJS y fueron un dolor de cabeza en su momento.

En este articulo te hablaré sobre un tema básico que toda persona que desarrolle debe comprender, para evitar errores en el programa. Estoy hablando de cómo funciona el mecanismo con el cual las variables son copiadas de un lugar a otro.

Los tipos de datos de un lenguaje describen los elementos básicos que pueden ser utilizados en un lenguaje.

Dependiendo de dónde busques, encontraras que en JavaScript (JS) hay entre 6 a 9 tipos de datos y estructuras con las cuales podemos trabajar. Nosotros definiremos 5 tipos de datos primitivos (datos que no son objetos y que no tienen métodos) y los tipos de datos no primitivos, conocidos como objetos, los cuales pueden dividirse en estructuras mas complejas.

Tipos de datos primitivos

  • Undefined
  • null
  • Boolean
  • String
  • Number

Tipos de datos no primitivos

Objects

  • Array
  • Date
  • Object
  • Set (entre otros).

Entonces ¿Cuál es la diferencia entre los tipos de datos primitivos y los objetos? La respuesta es la mutabilidad. Para entender este punto veamos lo siguiente.

Asignaciones de variables primitivas

El ejemplo a continuación, nos ayudará a entender el procedimiento que se sigue cuando realizamos una asignación de variables en JS.

Asignación de variables en JS

Cuando el código anterior es ejecutado, JS realizará 3 cosas:

  1. Creará un identificador para la variable (varNumber, varString, por ejemplo).
  2. Separará una dirección de memoria.
  3. Asignará el valor a la dirección separada.

Hasta aquí todo bien, vemos que en la siguiente tabla están las variables que declaramos antes.

Representación de la memoria de las variables en el programa

Ahora lo que haremos será asignar una variable a otra nueva, con el siguiente código:

Copia de variables

Nuestra tabla habrá cambiado ya que se agregan mas variables, veamos como luce ahora…

Representación de la copia de variables

Observamos que las dos variables nuevas contienen lo mismo, esto es lo que pasa cuando decimos que igualamos una variable a otra. Entonces, ¿qué pasa si cambiamos el valor de varCopyNumber?, ¿también cambiará el de varNumber? pues apuntan a la misma dirección de memoria… Probemos para ver qué sucede:

Modificación de una variable

Ocurrió algo interesante al incrementar el contenido de varCopyNumber. Observemos la siguiente tabla:

Representación de modificación de una variable

Como podemos ver, la respuesta es un rotundo no. Y ¿Por qué no? Esto se debe a que los tipos de datos primitivos de JS son inmutables, por ende, cuando JS resuelva que varCopyNumber es ahora 11, se separará nueva memoria y apuntará a éste. Esto ocurrirá cada que actualicemos las variables con tipos de datos primitivos.

El lugar donde sucede lo anterior, es conocido como Call Stack. No detallaremos mucho su funcionamiento, sin embargo, podemos hacernos la idea de que es una pila en donde se irán depositando las variables que vamos utilizando.

Representacion del Stack en JS

También tenemos otra estructura en JS conocida como Heap, en la cual serán acomodados los objetos de forma dinámica. En esta región no tenemos que preocuparnos por separar más memoria para arreglos. Para entender cómo funciona debemos pasar a las asignaciones de variables no primitivas.

Asignaciones de variables no primitivas

Veamos el ejemplo de un arreglo de números simple:

Asignación de un Arreglo

Cuando el código anterior es ejecutado, JS realizará 4 cosas:

  1. Creará un identificador para la variable (array).
  2. Separará una dirección de memoria en el Stack.
  3. Se asignará el valor a una dirección en el Heap
  4. La dirección de en el Heap es guardada en el Stack.

A diferencia de las variables primitivas, en el stack no vemos el contenido de la variable como antes, en su lugar vemos la dirección del Heap donde están guardadas, puede parecer un poco confuso, pero sigamos adelante.

Representación del Stack y del Heap

¿Qué pasa cuando modifico mi arreglo?

Inserción de datos al arreglo

Lo que se modificará será el contenido en el Heap, esto le da la propiedad de mutabilidad a los objetos. Un ejemplo de lo práctico de esto, es que no tenemos que cuidar el tamaño del arreglo cada que hagamos un push, JS se encarga de separar la memoria, manteniendo la misma dirección en el stack.

Representación del Stack y del Heap

Ahora veamos el siguiente caso:

Contenido de un arreglo y su copia

¿Qué fue lo que ocurrió? Al hacer un copyArray.push(6) sobre copyArray, el Heap será modificado. Si observamos su contenido, veremos “[1,2,3,4,5,6]”, pero si revisamos también array nos encontraremos con exactamente el mismo contenido; “[1,2,3,4,5,6]”. Veamos la tabla para descubrir qué sucedió.

Representación del Stack y del Heap

Como podemos ver, al realizar el push lo único que cambio fue el contenido en el Heap, por lo que tanto array como copyArray seguirán con la misma referencia en el stack, hasta que una de las dos sea sobrescrita con otra cosa.

Caso problematico

Es importante no tomar a la ligera este comportamiento en los objetos, ya que podría ocasionar comportamientos indeseados en nuestros programas. Veamos el siguiente ejemplo:

Copia de un objeto

Según la información del método Object.Assign, se copiarán los valores de todas las propiedades numerables del objeto fuente. Entonces, ¿Cuál será el contenido de los dos objetos (persona y copyPersona)?

Contenido de un objeto y su copia

Ahora ya sabes porqué aunque el objeto persona fue copiado, el arreglo de tarjetas fue modificado en los dos objetos.

Solución practica

Algo sencillo de implementar es romper todas las referencias, con esto podemos lograr lo siguiente:

Copia de un objeto sin referencias

Si realizamos los mismos cambios que antes, pero en lugar de Object.Assign utilizamos lo anterior, podremos ver que los objetos están completamente aislados. Recuerda que si la eficiencia crucial en tu aplicación, deberás buscar mejores opciones para realizar la copia a profundidad.

Contenido de un objeto y su copia sin referencias

Concluyendo, toda variable primitiva se copia por valor y los objetos por referencia. Si experimentas problemas con objetos modificados y no sabes el porqué, deberías primero revisar cuidadosamente cómo manipulas los objetos en tu aplicación.

Share on facebook
Share on twitter
Share on linkedin

One Reply to “¿Qué hay tras las variables en JavaScript?”

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

¡Conozcámonos mejor!

Te haremos llegar las novedades de SoldAI, ofertas exclusivas, notificaciones, y mucho más.

¡Deja tu correo, tenemos mucho que contarte!