JavaScript mutable e inmutable

Índice
  1. ¿Por qué utilizar datos inmutables?
  2. Herramientas de inmutabilidad
  3. Uso de descriptores de propiedades
  4. Matrices inmutables
  5. Otros métodos

Cuando me sumergí por primera vez en JavaScript y la programación, nunca pensé en datos inmutables. Solía ​​decir que el animal es el panda y luego el animal es el león.

var animal = 'panda';animal = 'lion';

¡Era libre de hacer lo que quisiera con mis datos! Pero… las cosas cambiaron… Crecí. La gente empezó a decirme: “si puedes, siempre deberías usar const”. Así que lo hice obedientemente. Pero no entendía muy bien por qué.

¿Por qué utilizar datos inmutables?

Porque a veces el código cambia cosas que no quieres que cambien. Sé que es una respuesta muy poco convincente, déjame que te la muestre con un ejemplo.

Digamos que tenemos un sitio de comercio electrónico.

Módulo: checkout.js

// First we import a function called validate address to check if our users entered a valid addressimport validateAddress from 'address-validator'const checkout = (user, cart) = { //... checkout code var userAddress = user.address // Checking if the address is valid const validAddress = validateAddress(userAddress); // If the address is valid then if (validAddress) {  //... proceed to checkout }}

Digamos que obtuvimos nuestro validador de direcciones instalando un npmpaquete.

$ npm install address-validator

Todo funciona como se espera, pero un día se lanza una nueva versión y se introduce una nueva línea de código en el paquete que se ve así:

Módulo: validationAddress.js

const validateAddress = (address) = { address = '123 My Street, Bring Me Free Goods, USA'; return true;}

Ahora la variable userAddresssiempre será igual al valor de la dirección. Puedes ver por qué esto es un problema.

Este problema específico se puede resolver mediante el uso de la inmutabilidad, pero también se puede resolver con un alcance adecuado. ¡Intenta averiguar cómo!

Por supuesto, el código malicioso es un caso extremo, pero hay muchas formas en las que los datos inmutables pueden ayudarle a escribir mejor código. Por ejemplo, un error muy común es mutar accidentalmente la propiedad de un objeto.

Módulo: accidental-change.js

const userJack = {name: 'Jack Misteli'};// I want to make a copy of user to do stuff with itconst user2 = userJackuser2.name = 'Bob'// Because we didn't do a copy:// userJack.name === 'bob'

Este tipo de error puede ocurrir muy a menudo.

Herramientas de inmutabilidad

La herramienta de inmutabilidad más intuitiva es utilizar const.

const animal = 'panda';// This will throw a TypeError!panda = 'lion';

constEs genial, pero a veces sólo da la ilusión de inmutabilidad.

Módulo: example-checkout.js

const user = { name: 'Jack Misteli', address: '233 Paradise Road', bankingInfo: 'You wish!'};const maliciousAddressValidator = (user) = { user.address = 'Malicious Road'; return true;};const validAddress = maliciousAddressValidator(user);// Now user.address === 'Malicious Road' !!

Hay diferentes formas de resolver este problema e introducir la inmutabilidad es una de ellas.

Primero podemos utilizar el Object.freezemétodo.

const user = { address: '233 Paradise Road'};Object.freeze(user)// Uing the same dodgy validateUserAddressconst validAddress = maliciousAddressValidator(user);// Now user.address === '233 Paradise Road' !!

Un problema Object.freezees que no afecta a las subpropiedades. Para llegar a todas las subpropiedades, puedes escribir algo como:

const superFreeze = (obj) = { Object.values(obj).forEach(val ={  if (typeof val === 'object')    superFreeze(val)  })  Object.freeze(obj)}

Otra solución es utilizar proxies si necesitas flexibilidad.

Uso de descriptores de propiedades

En muchos sitios, verá que puede modificar los descriptores de propiedades para crear propiedades inmutables. Y eso es cierto, pero debe asegurarse de que configurabley writeableestén configurados como falsos.

// Setting up a normal getterconst user = { get address(){ return '233 Paradise Road' },};console.log(Object.getOwnPropertyDescriptor(user, 'address'))//{//  get: [Function: get address],//  set: undefined,//  enumerable: true,//  configurable: true//}const validAddress = maliciousAddressValidator(user);// It looks like our data is immutable!// user.address ===  '233 Paradise Road'

Pero los datos siguen siendo mutables, sólo que es más difícil mutarlos:

const maliciousAddressValidator = (user) = { // We don't reassign the value of address directly // We reconfigure the address property  Object.defineProperty(user, "address", {    get: function() {     return 'Malicious Road';   }, });};const validAddress = maliciousAddressValidator(user);// user.address === 'Malicious Road'

¡Arrr!

Si establecemos writable y configurable en falso obtenemos:

const user = {};Object.defineProperty(user, "address", {value: 'Paradise Road', writeable: false, configurable: false});const isValid = maliciousAddressValidator(user)// This will throw:// TypeError: Cannot redefine property: address

Matrices inmutables

Las matrices tienen el mismo problema que los objetos.

const arr = ['a','b', 'c']arr[0] = 10// arr === [ 10, 'b', 'c' ]

Bueno, puedes utilizar las mismas herramientas que usamos anteriormente.

Object.freeze(arr)arr[0] = 10// arr[0] === 'a'const zoo = []Object.defineProperty(zoo, 0, {value: 'panda', writeable: false, configurable: false});Object.defineProperty(zoo, 1, {value: 'lion', writeable: false, configurable: false});// zoo === ['panda', 'lion']zoo[0] = 'alligator'// The value of zoo[0] hasn't changed// zoo[0] === 'panda

Otros métodos

Existen otros trucos para mantener tus datos seguros. Te recomiendo que consultes nuestro artículo sobre las trampas de proxy para descubrir otras formas de hacer que tus datos sean inmutables. Aquí solo hemos tocado la superficie.

En esta publicación, exploramos opciones para introducir inmutabilidad sin cambiar la estructura y el estilo de nuestro código. En futuras publicaciones, exploraremos bibliotecas como Immutable.js, Immer o Ramda para corregir código inmutable.

SUSCRÍBETE A NUESTRO BOLETÍN 
No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

Deja una respuesta

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

Subir

Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion