Crea una cuenta o inicia sesión

¡Continúa aprendiendo sin ningún costo! Únete y comienza a potenciar tu carrera

Mutable o Inmutable

3/28
Recursos

Los conceptos de mutabilidad e inmutabilidad son muy importantes para los siguientes métodos de arrays. Existen métodos mutables que cambian el array original; e inmutables que devuelven un array diferente al original.

Referencias en memoria

En JavaScript, cada estructura está guardada en una referencia en memoria, por lo que si cambiamos un elemento en el array, también lo haremos en esa referencia. Al clonar arrays, se crea un nuevo array que tiene las mismas referencias en memoria que el original, por lo que si se realiza un cambio en el original, también cambiará en la copia.

const original = [1,2,3]
const copia = original
copia[0] = "Hola"

console.log(original) // [ 'Hola', 2, 3 ]

Diferencia entre mutabilidad e inmutabilidad

Con lo mencionado anteriormente, mutable es aquella acción que cambia el valor en la referencia en memoria del elemento del array original, provocando que cambien el original y la copia. Inmutable es la acción en la que se cambia el valor, pero en una referencia diferente del original, provocando que el original siga igual.

La mutabilidad es más flexible y una buena opción si se requiere cambiar, actualizar o eliminar datos; pero esto puede ocasionar fallos o resultados erróneos en nuestra aplicación. La inmutabilidad es más exigente, te permite generar nuevas estructuras para manejarlas sin cambiar la original; pero esto puede provocar que la memoria colapse.

Por lo que, ¿cuál es mejor? La respuesta es ninguna, cada uno te permite manejar estructuras de datos, por ende es necesario identificar cuál forma es la adecuada a aplicar en un algoritmo.

Contribución creada por: Andrés Guano.

Aportes 25

Preguntas 2

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

o inicia sesión.

No te quedo claro la clase lee esto.

En JS los datos asignados a una variable pueden ser de dos tipos:

Primitive type (undefined, null, boolean, number, string, symbol), Reference type (objects, arrays , functions).

Una de las diferencia entre estas dos, está en la forma como se almacenan estos datos en memoria, para ser más claro un ejemplo.

let name = 'Javier';

let name2 = name;

let person = {name: 'javier'};

let person2 = person;

Cuando creamos name js crea un espacio en memoria y guarda su valor, ahora cuando creamos name2 js continúa crea un nuevo espacio en memoria y asigna el mismo valor de la varible name de esta forma el valor de la variable name2 es totalmente independiente a name.

Ahora si creamos la variable person como un objeto que contiene un name, y si luego creamos otra variable person2 y le asignamos el mismo objeto person, aquí es donde la cosa cambia con respectos a los datos primitivos, en este caso js guardara el objeto person2 como una referencia o apuntador al objeto person, es decir que ambas variables apuntan al mismo objeto en memoria.

Ahora si entendamos Mutable o Inmutable.

Mutable: es algo que se puede cambiar o agregar.

Inmutable: es algo que no puede cambiar ni agregar.

Los valores primitivos en js son algo agregado donde solo se pueden reasignar y por lo tanto, todos estos valores son inmutables. Entendamos con un ejemplo.

console.log(name); //javier
console.log(name2); //javier

name2 = 'platzi';

console.log(name); //javier
console.log(name2); //platzi''

Si imprimimos name y name2, ambas nos dan javier, pero si reasignamos un valor de name2 y volvemos a imprimir ocurre que solo cambia el valor de name2, lo que demuestra que js guardas estás variables de forma separada, aun cuando el valor de name2 se copio de name. Por eso los valores primitivos son inmutables.

ahora hagamos lo mismo con los objetos.

console.log(person); //{name: 'javier'}
console.log(person2); //{name: 'javier'}

person2.name = 'platzi';

console.log(person); //{name: 'platzi'}
console.log(person2); //{name: 'platzi'}

Al inicio obtenemos las mismas propiedades, ahora cambiemos una de las valores de las propiedades y veremos que js cambio el valor tanto de person y peron2, esto debido a que person2 se creo haciendo referencia al objeto person, con reference type js crea una referencia al mismo objeto y el objeto permanece mutable.

ya que el mismo objeto es mutable se puede cambiar o se pueden agregar nuevas propiedades al mismo objeto.

En es6 se creo un operador de propagación que permirte copias un objeto de forma segura sin hacer referencia al mismo objeto y sería así.

let person2 = {...person}

Ahora vuelve a ver la clase y veras como todo es más claro y entendible.

Recomiendo esta charla (en ingles) sobre este tema, super increíble: https://www.youtube.com/watch?v=Wo0qiGPSV-s&ab_channel=JSConf
.
Son 30 minutos valiosos 😃

Paso por referencia vs Paso por valor

Por tipos, los primitivos se pasan por valor y los objetos por referencia

Ejemplo gráfico:

Mutable es un tipo de variable que se puede cambiar. En JavaScript, solo los objetos (objects) y las matrices (arrays) son mutables, no valores primitivos.

(Puedes hacer que el nombre de una variable apunte a un nuevo valor, pero el valor anterior todavía se mantiene en la memoria. De ahí la necesidad de la recolección de basura).

Un objeto mutable es un objeto cuyo estado puede modificarse después de su creación.

Los inmutables son los objetos cuyo estado no se puede cambiar una vez creado el objeto.

Las cadenas y los números son inmutables. Entendamos esto con un ejemplo:

var immutableString = “Hola”;

// En el código anterior, se crea un nuevo objeto con valor de cadena.

immutableString = immutableString + “Mundo”;

// Ahora agregamos “Mundo” al valor existente.

Al agregar “immutableString” con un valor de cadena, ocurren los siguientes eventos:

Se recupera el valor existente de "immutableString"
"World" se agrega al valor existente de "immutableString"
El valor resultante luego se asigna a un nuevo bloque de memoria
El objeto "immutableString" ahora apunta al espacio de memoria recién creado
El espacio de memoria creado anteriormente ahora está disponible para la recolección de basura.

Spread Operator

Utilizando el spread operator, cogemos los valores de person y los insertamos directamente en X. Así evitamos anidar un abjeto dentro de otro
Con el spread operator, podemos sumar arrays, hacer copias, añadir nuevos elementos…

Te das cuenta de que aprendes cuando comprendes las referencias en memoria de js 😃

Casi siempre es mejor clonar una lista en lugar de mutarla. Nos ayuda a evitar Side Effects.

Con las copias tenemos el mismo contenido pero distinta referencia en memoria.

// Reto clase
        const todo = [
            {name: "Comprar pan", status: true},
            {name: "Ir al gym", status: false},
            {name: "Terminar proyecto", status: false},
            {name: "Estudiar en Platzi", status: true},
        ];

        const list = document.getElementById('todo');

        todo.forEach((item) => {
            list.innerHTML += `
            <li>
                <label><input type="checkbox" ${item.status ? `checked` : ''}>${item.name}</label>
            </li>
            `
        })

Mutable: que muta, que puede cambiar.
inmutable: que no muta, que no cambia.

Primitive type: number, string, boolean, undefined, null
Reference type object, array , function

let array = [1,2,3,4,5,6]

array.metodo(funcion) // [2,4,6]

si vemos nuestro array original, podemos ver que ha mutado …

console.log(array) // [2,4,6] 

esta bien si es lo que deseamos hacer, pero si quisiéramos evitar esto, podríamos copiar nuestro array original

let array = [1,2,3,4,5,6]
let copy = [...array]

console.log(array) // [1,2,3,4,5,6]
console.log(copy) // [1,2,3,4,5,6]

y modificar la copia

copy.metodo(funcion) // [2,4,6]

si miramos en consola, vemos que nuestro copia ha mutado, pero nuestro array original sigue igual

console.log(array) // [1,2,3,4,5,6]
console.log(copy) // [2,4,6]

esto podría ser una solución, pero estaríamos utilizando mas recursos en memoria y en ocasiones nuestro array original será un array muy grande y no es muy optimo realizar copias y abusar de los recursos de memoria.
podemos llamar un método sobre el array original y almacenar el resultado en una variable

let array = [1,2,3,4,5,6]
let arrayModificado = array.metodo(funcion)

si miramos en consola, podemos ver el nuevo array y nuestro array original igual

console.log(array) // [1,2,3,4,5,6]
console.log(arrayModificado) // [2,4,6]

pero que esta pasando aqui … ¿no seria lo mismo que realizar una copia y mutar la copia?, ¡no!, es diferente.
si hacemos console.table(array) podemos ver el índice y los valores del array original

índice - Valor 
0 - 1
1 - 2
2 - 3
3 - 4
4 - 5
5 - 6

lo que el método hace sobre el array original es realizar la función que le indiquemos, es este caso solo nos deja los indices que contengan elementos con números pares y los almacena dentro de la variable arrayModificado.
si hacemos console.table(arrayModificado)

índice - Valor 
0 - 2
1 - 4
2 - 6

¿seguiría siendo lo mismo?,¿realizamos una copia y mutamos la copia?, no exactamente.
si es cierto que retornamos una nuevo array y lo almacenamos en una variable (arrayModificado), pero los valores almacenados dentro de sus indices están haciendo referencia al array original.
una forma de verlo mas clara es como si tuviéramos esto console.table(arrayModificado)

índice - Valor 
0 - array[1]
1 - array[3]
2 - array[5]

si queremos comprobarlo, comparamos los valores y observamos que nos retorna true, esta haciendo referencia al mismo espacio en memoria

console.log(array[1] === arrayMofificado[0]) // true 
console.log(array[3] === arrayMofificado[1]) // true 
console.log(array[5] === arrayMofificado[2]) // true 

este nuevo array y sus valores en sus indices están haciendo referencia al array original, de esta forma no estaríamos mutando al array original ni realizando copias de el, desde el nuevo array estaríamos haciendo referencia a los valores del array original y eliminando los indices que tengan números impares.
todas estas instrucciones que queremos que ejecute, las indicamos en el cuerpo de la función que pasamos por parámetro al método.
.
.
podemos en un nuevo array hacer referencia a indices del array original y añadir o eliminar otros elementos, teniendo lo mejor de las formas anteriores, no copiando ni mutando el original, haciendo referencia al array original aprovechando mejor los recursos de la memoria y teniendo nuestro array original igual y un nuevo array con indices referenciados del array original.

En breves palabras. Si al ejecutar un método de manejo de arrays me retorna un nuevo array se aplica inmutabilidad, pero si al ejecutar un método de manejo de arrays y no retorna un array nuevo, sino que modifico el mismo array, se llama mutabilidad.

Si aun no les quedó claro este concepto, les recomiendo volver al curso Intermedio de Programación Orientada a Objetos y ver este video sobre Funcionamiento de Memoria en JavaScript. En resumen, los datos primitivos cuando se los copia, no hacen copias por referencia, mientras que las estructuras complejas, si hacen copias por referencia, por lo que puedes sin quieres afectar al mismo objeto. Si les interesa conocer mas a fondo como funciona esto, deberian tomar cursos de C y C++ ya que estos abordan términos como punteros y referencias.
Pero en resumen:

 class Person{
    constructor(name){
        this.name=name;
    }
}

let danny=new Person('danny');
let copy=danny; //danny apunta a copy y copy apunta a danny, cambiar valores en estos
//afecta al original y a la copia
//Cuando creo la copia y el original
console.log(danny);
console.log(copy);
//cambiar original
danny.name='juan';
console.log(copy);
//cambiar copia
copy.name='copia';
console.log(danny);

éste teacher es genial _

Eso de un árbol y que solo cambia si algo cambio es el fundamento del Virtual DOM que usan React y Vue, por eso son tan rápidos. Angular utiliza el Incremental DOM, que esta basado en la memoria…

Recomiendo mucho este tutorial sobre el una pequeñisima intro al paradigma funcional y las funciones o metodos que ya nos provee el propio JS

https://www.youtube.com/watch?v=3eLx9syx8iI&t=948s

Características de una función pura:

  • El valor que retorna depende sólo de los argumentos de entrada, es decir. El valor de retorno no cambiará si los valores de entrada no cambian
  • No puede modificar nada que este fuera de su ámbito.

La copia es una referencia en memoria, solo copia los elementos cambiados, creando una nueva estructura de datos on referencias de memoria y nuevos elementos.

Cuando cambiamos el array original, hacemos una mutación(mutable) y cuando generamos un nuevo estado: Estamos creando una estructura de datos inmutable

Hay que entender esto. Si tienes una variable con un array a la cual ponemos array1, y otra variable array2 a la cual le asignamos el array1. Si cambiamos los valores de array2, estos cambios también se veran reflejados en el array1 que es el array original, por que el array lo que guarda es una referencia en memoria.

let array1 = [1,2,3,4,5];
let array2 = array1;

array2.push(6)

console.log(array1) // [1,2,3,4,5,6]
console.log(array2) // [1,2,3,4,5,6]

Para crear un array que no este enlazado a la referencia del original hay varias maneras. La que me gusta usar es la función Array.from() de esta manera:

let array1 = [1,2,3,4,5];
let array2 = Array.from(array1); // [1,2,3,4,5]

array2.push(6);
console.log(array1) // [1,2,3,4,5]
console.log(array2) // [1,2,3,4,5,6]

De esta manera el nuevo array es una copia totalmente desligada de la referencia y ya no afectara al array original

Aquí entra el concepto de shallow copy and deep copy
https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy

Tareas checkbox

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>For each</title>
</head>

<body>
  <div id="app"></div>
  <script>
    const tasks = [
      { task: 'bañarme', status: true },
      { task: 'curso arrays', status: false },
      { task: 'certificado eps', status: true },
      { task: 'limpiar', status: false }
    ]
    const app = document.getElementById('app')
    tasks.forEach(task => {
      app.innerHTML += `
        <div>
          <input type="checkbox" ${task.status && 'checked'}>${task.task}</input>  
        </div>
      `
    })
  </script>
</body>

</html>

De forma sencilla podemos entender los conceptos de Mutabilidad y Inmutabilidad como que …

La Mutabilidad nos permite cambiar el tipo de dato de una variable, los objects y arrays son mutables.

y la Inmutabilidad no nos permite cambiar el tipo de dato de una variable, los valores primarios son inmutables.

Estaba buscando esta respuesta desde hace rato … por fin, esto es MUY importante, sino van a haber choques en la memoria y van a pasar cosas muy raras con los resultados al usar las variables o en este caso los arrays

Mutacion: El elemento original lo estamos cambiando
Inmutabilidad:Clonamos el elemento original y apartir de esta clonacion realizamos los cambios

Pequeña ayuda:

Si realmente te importa entender todo lo que esta sucediendo, toma los 2 cursos de poo de platzi. Ahi entenderas mutabilidad, referencias, copias, inmutabilidad, y algormitos que te permitan generar copias reales y no referencias que sean un caos.

Para un mayor avance, toma el curso de introducion a los algoritmos. Debes saber lo que es hacer un bucle dentro de otro bucle y cuan costoso es eso.

Exitos!

este curso me parece muy necesario y buenisimo!!! hasta aqui van 5 stars!

En resumen, cuando utilizamos el mismo array sin modificaciones se llama MUTACIÓN.
Mientras que si copiamos o clonamos el array anterior con modificaciones, se le llama estructura de datos inmutable.
Para ser mas clara, aquí tenemos un ejemplo visual:

//tenemos este array, como solo copiamos el array se le llama mutación:
let arrayOriginal = ['1',true,'pepe'];
let copia = arrayOriginal ;

//ahora en este caso usamos otro array pero modificandolo, ejemplo:
let array2 = ['luisa','fernando','pedro'];
let inmutacionArray = array2.push(9);
console.log('mutacion',copia); //en este, tenemos la mutacion(copia de array original)
console.log('inmutabildad',array2); //y en este, tenemos el array original(hablando de array2) mas una modificación(inmutabilidad)

PD : Te invito a probar este código para que sea mas entendible 😃

Agregamos después de la etiqueta li, el input de tipo (type) checkbox para marcar las tareas realizadas.

<div id="homeworks"></div>
    <script>
        const tareas = [
            {materia:"Matematicas", tarea:"Algebra pag 2"},
            {materia:"Quimica", tarea:"electrones"},
            {materia:"programacion", tarea:"usar foreach"},
            {materia:"diseño", tarea:"retoque foto"},
        ];

        let homeworks = document.getElementById("homeworks");
        tareas.forEach(item2 => {
            homeworks.innerHTML += `
            <li>${item2.tarea} - materia: ${item2.materia}</li><input type="checkbox">`;
        });
    </script>