Actualizaciones de arrays inmutables con Array.prototype.with

Recientemente, los navegadores incorporaron un nuevo método interoperable que puedes llamar en Arrays: Array.prototype.with().

Browser Support

  • Chrome: 110.
  • Edge: 110.
  • Firefox: 115.
  • Safari: 16.

Source

En este artículo, se explora cómo funciona este método y cómo usarlo para actualizar un array sin mutar el array original.

Introducción a Array.prototype.with(index, value)

El método Array.prototype.with(index, value) devuelve una copia del array en el que se llama con el index establecido en el nuevo value que proporcionas.

En el siguiente ejemplo, se muestra un array de edades. Te gustaría crear una copia nueva del array y cambiar la segunda edad de 15 a 16:

const ages = [10, 15, 20, 25];

const newAges = ages.with(1, 16);
console.log(newAges); // [10, 16, 20, 25]
console.log(ages); // [10, 15, 20, 25] (unchanged)

Desglose del código: ages.with(...) devuelve una copia de la variable ages sin modificar el array original. ages.with(1, …) reemplaza el segundo elemento (index = 1). ages.with(1, 16) asigna el segundo elemento a 16.

Así pudiste crear una copia nueva del array con una modificación.

Esto es muy útil cuando quieres asegurarte de que el array original no cambie, y este artículo abarca algunos de los casos de uso para esto. Pero, por ahora, observa lo que habría sucedido si hubieras usado la notación de corchetes:

const ages = [10, 15, 20, 25];

const newAges = ages;
newAges[1] = 16;
console.log(newAges); // [10, 16, 20, 25]
console.log(ages); // [10, 16, 20, 25] (Also changed 🙁)

Como puedes ver, la variable ages también se modificó en este ejemplo. Esto se debe a que, cuando asignas ages = newAges, JavaScript no copia el array, sino que crea una referencia al otro array. Por lo tanto, cualquier cambio en uno también afectará al otro, ya que ambos apuntan al mismo array.

Array.prototype.with() e inmutabilidad

La inmutabilidad es la base de muchas bibliotecas y frameworks de frontend, como React (y Redux) y Vue, por nombrar algunos.

Además, otras bibliotecas y frameworks no necesariamente requieren inmutabilidad, pero la fomentan para un mejor rendimiento: Angular y Lit

Por lo tanto, los desarrolladores a menudo tenían que usar otros métodos que devolvían copias de arrays, lo que sacrificaba la legibilidad del código:

const ages = [10, 15, 20, 25];

const newAges = ages.map((age, index) => {
    if (index === 1) {
         return 16;
    }
    return age;
});

console.log(newAges); // [10, 16, 20, 25]
console.log(ages); // [10, 15, 20, 25] (Remains unchanged)

Este es un ejemplo de Codepen sobre cómo se puede usar .with() en React en combinación con useState para actualizar de forma inmutable un array de elementos:

Dado que el método .with() devuelve una copia del array, puedes encadenar varias llamadas a .with() o incluso otros métodos de array. En el siguiente ejemplo, se muestra cómo incrementar la segunda y la tercera edad del array:

const ages = [10, 15, 20, 25];

const newAges = ages.with(1, ages[1] + 1).with(2, ages[2] + 1)

console.log(newAges); // [10, 16, 21, 25]
console.log(ages); // [10, 15, 20, 25] (unchanged)

Otros métodos nuevos inmutables

Recientemente, otros tres métodos se volvieron interoperables:

Según MDN, estos tres métodos son la versión de copia de sus contrapartes. Estos métodos también se pueden usar cuando se espera o prefiere la inmutabilidad.

En conclusión, las actualizaciones inmutables se pueden lograr más fácilmente en JavaScript con uno de los cuatro métodos que se presentan en este artículo. Específicamente, el método .with() facilita la actualización de un solo elemento del array sin modificar el array original.