Object-Oriented Programación en JS: 3. Manipulación de Datos

Explicando la reflexión, enumeración y supresión - 3 temas criticales de trabajar con datos en objetos.

Como ya hemos visto en el artículo anterior de OOP, podemos usar el método Object.create() para crear un nuevo objeto que enlaza a otro objeto, y cuando tenemos esta relación padre-hijo, el objeto padre se llama Prototipo del hijo.

En el siguiente ejemplo, myPerson se consideraría el Prototipo de chris.


// create a parent object
const myPerson = {
  arms: 2,
  legs: 2,
};

// create a child object that links to parent object
const chris = Object.create(myPerson);

Si quieres saber si un objeto tiene una propiedad, podemos buscarla utilizando la notación de punto o de corchetes. Y ¿si buscamos una propiedad que no existe en el objeto? Por ejemplo, chris.hands daría el valor undefined. Pero ¿Qué pasa si queremos buscar una propiedad que existe más arriba en el vínculo prototípico?


// create a parent object
const myPerson = {
  arms: 2,
  legs: 2,
};

// create a child object that links to parent object
const chris = Object.create(myPerson);
console.log(chris.hands);
// undefined

Si intentamos hacer referencia a chris.arms, el intérprete de JavaScript primero va a buscar en el objeto chris,verá que ahí no lo existe, y intenta buscar más arriba del vínculo prototípico, hasta myPerson, y ahí verá que myPerson si tiene la propiedad arms, y devolverá el valor correspondiente, 2.

So, por usar notación de punto o corchetes para buscar una propiedad no necesariamente garantiza que una propiedad existe en el propio objeto - puede ser que la existe en el prototipo del objeto. Así que, cómo nos aseguramos que una propiedad existe en el propio objeto?

Una manera de lograr esto es por utilizar el método hasOwnProperty. Vamos a intentar:


// create a parent object
const myPerson = {
  arms: 2,
  legs: 2,
};

// create a child object that links to parent object
const chris = Object.create(myPerson);
console.log(chris.hasOwnProperty('arms'));
// false

Podemos ver del ejemplo anterior que no, el objeto chris su mismo no tiene la propiedad arms.

Otra manera de comprobar si un objeto tiene una propiedad: podemos usar el for...in loop para iterar sobre las propiedades de un objeto, por ejemplo:


for (let key in chris) {
  console.log(key);
}
// arms
// legs

El problema con esto es que cuando yo console.log() cada propiedad del objeto, el for..in loop no solo va a iterar sobre las clave del propio chris, sino también va a iterar sobre cualquieres claves he creado el el prototipo de ese objeto. Así que podemos combinar un for..in loop con el método hasOwnProperty:


for (let key in chris) {
  console.log(key, chris.hasOwnProperty(key));
}
// arms false
// legs false

En el ejemplo anterior podemos usar hasOwnProperty para filtrar las propiedades que no nos importa. Una cosa para tener en cuenta durante este proceso es que el orden de claves en un objeto no es necesariamente guarantizado. Así que, si necesitas una solución que guarantiza que las claves siempre están en el orden correcto, puedes agarrar una estructura de datos diferente como un Map.

También puedes usar un array, y si estás usando algún tipo de método para iterar sobre el array, no tienes que preocupar por las propiedades que existen arriba del vínculo prototípico, pero es posible que haya inconvenientes de funcionamiento por usar un array en lugar de un objeto. Esto puedes aprender por estudiar Notación Big O, especificamente sobre tiempo constante de Objetos y tiempo linear de elementos Array.

Si queremos eliminar una propiedad de un objeto, por ejemplo, si tenemos una propiedad en chris:


const chris = Object.create(myPerson);
chris.hands = 2;
console.log(chris);
// { hands: 2 }

¿Y si queremos eliminar esta propiedad de chris? Podemos usar la clave delete:


const chris = Object.create(myPerson);
chris.hands = 2;
console.log(chris);
// { hands: 2 }
delete chris.hands;
console.log(chris);
// {}

Sin embargo, ¿Qué pasaría si intentáramos eliminar una propiedad que existe más arriba del vínculo prototípico?


const chris = Object.create(myPerson);
chris.hands = 2;
console.log(chris);
// { hands: 2 }
delete chris.hands;
console.log(chris);
// {}
delete chris.arms;
console.log(chris.arms);
// 2

¿Aún tiene chris la propiedad arms - la que existe más arriba del vínculo? Sí - la tiene. Así que no pude eliminar una propiedad arriba del vínculo con delete. Para eliminar esa propiedad arms, tendría que eliminar el vínculo entre chris y myPerson, o eliminar arms directamente de myPerson. Cuando tenemos propiedades que existen arriba del vínculo que no se puede eliminar, esas están llamados propiedades no-configurables.

Cualquieras propiedades que existen en objetos por defecto, como Object.hasOwnProperty o Array.push, se consideran propiedades no-configurables. Existen por defector - están ahí nativamente - y no las pueden eliminarse.