Tratamos con objetos en JavaScript

En este artículo, el autor, un desarrollador front-end, dio una visión general de las principales formas de crear, modificar y comparar objetos JavaScript.


Los objetos son uno de los conceptos básicos en JavaScript. Cuando comencé a estudiarlos, me parecieron bastante simples: solo un par de claves y valores, como se describe en teoría.

Solo después de un tiempo comencé a darme cuenta de que el tema es mucho más complicado de lo que pensaba. Y luego comencé a estudiar información de varias fuentes. Algunos de ellos dieron una buena idea sobre el tema, pero no pude ver la imagen completa de inmediato.

En esta publicación, traté de cubrir todos los aspectos del trabajo con objetos en JS, sin profundizar en detalles individuales, pero sin perder detalles importantes que lo ayudarán a comprender el tema y sentirse más seguro durante su estudio posterior.

Entonces, comencemos con lo básico.

Objeto


Un objeto en JavaScript es simplemente una colección de propiedades, cada una de las cuales es un par clave-valor. Se puede acceder a las teclas utilizando la notación punteada ( obj.a ) o entre corchetes ( obj ['a'] ).

Recuerde que los corchetes deben usarse si la clave es:

  • no es un identificador de JavaScript válido (tiene un espacio, un guión, comienza con un número ...)
  • es una variable

Una de las propiedades que obtienen los objetos en JS cuando se crean se llama Prototipo , y este es un concepto muy importante.

Prototipo


Cada objeto en JavaScript tiene una propiedad interna llamada Prototipo . En la mayoría de los navegadores, puede referirse a él mediante la designación __proto__ .

Prototype es una forma de proporcionar herencia de propiedades en JavaScript. Para que pueda compartir la funcionalidad sin duplicar el código en la memoria. El método funciona creando una relación entre dos objetos.

En pocas palabras, Prototype crea un puntero de un objeto a otro.

Cadena prototipo

Cada vez que JS busca una propiedad en el objeto y no la encuentra directamente en el propio objeto, verifica la presencia de la propiedad en el objeto prototipo. Si no tiene ninguna propiedad, JS continuará buscando en el prototipo del objeto relacionado. Esto continuará hasta que JS encuentre una propiedad adecuada o llegue al final de la cadena.

Veamos un ejemplo:

var cons = function () {   this.a = 1;   this.b = 2; } var obj = new cons(); </i>  cons.prototype.b = 3; cons.prototype.c = 4; 

cons es un constructor (solo una función que se puede llamar usando el nuevo operador).

En la quinta línea, creamos un nuevo objeto, una nueva copia de los contras . Inmediatamente después de crear, obj también obtiene una propiedad prototipo.

Y ahora agregamos propiedades ( 'b', 'c' ) al prototipo del objeto cons .
Considera obj :

obj.a // 1 - todo es como antes , obj.a sigue siendo 1.
obj.c - obj no tiene propiedad c ! Sin embargo, como se mencionó anteriormente, JS ahora lo buscará en el prototipo obj y devolverá un valor de 4.

Ahora pensemos cuál es el valor de obj.b y en qué se convertirá cuando eliminemos obj.b.

Obj.b es 2. Asignamos la propiedad b , pero lo hicimos para el prototipo de contras , así que cuando verificamos obj.b , todavía obtenemos 2. Sin embargo, inmediatamente después de eliminar obj.b, JS ya no podrá encontrar b en o bj y, por lo tanto, continuará la búsqueda en el prototipo y devolverá el valor 3.

A continuación, quiero hablar brevemente sobre varias formas de crear un objeto y un poco más sobre prototipos.

Creación de objetos


Literal del objeto: let obj = {a: 1};
Creamos un objeto con la siguiente cadena de prototipo: obj ---> Object.prototype ---> null
Como puede adivinar, object.prototype es el prototipo del objeto, así como el final de la cadena del prototipo.

Object.create (): var newObj = Object.create (obj);
NewObj tendrá la siguiente cadena de prototipo: newObj ---> obj ---> Object.prototype ---> null

Constructor. Como en el ejemplo anterior, el constructor es solo una función JS que nos permite usar el nuevo operador para crear nuevas instancias del mismo.

Clases de ES6:

 class rectangle { constructor(height, width) { this.height = height; this.width = width; } getArea() { return this.height * this.width; } } let square = new rectangle(2, 2); 

Square es una instancia del constructor de rectángulos , por lo que podemos llamar a square.getArea () // 4 , square.width , así como a todas las funciones heredadas de object.prototype .

¿Qué método es mejor? Si planea crear varias instancias, puede usar ES6 o el constructor. Si planea crear un objeto una vez, es mejor especificar un literal, ya que esta es la forma más fácil.

Y ahora, cuando aprendimos sobre el prototipo y nos familiarizamos con todas las formas de crear nuevos objetos, podemos proceder a discutir uno de los aspectos más confusos asociados con los objetos.

Comparar y modificar objetos


En JavaScript, los objetos son de tipo de referencia

Cuando creamos un objeto, dejemos obj = {a: 1}; , la variable obj obtiene la dirección en la memoria del objeto, ¡pero no su valor! Es imprescindible comprender esta diferencia, ya que de lo contrario pueden producirse errores. Cuando creamos otro objeto let newObj = obj , en realidad creamos un puntero a cierta área de memoria obj , y no un objeto completamente nuevo.

Esto significa que al ejecutar newObj.a = 2 , en realidad cambiamos obj para que obj.a se convierta en 2.

Este enfoque lleva fácilmente a la aparición de errores, por lo que muchas empresas trabajan con objetos inmutables. En lugar de cambiar un objeto ya creado, nuevamente tendrá que crear un nuevo objeto (una copia del original) y realizar cambios en él. Así es como funcionan las bibliotecas importantes como Redux, y en general este es uno de los conceptos básicos de la programación funcional. Lee más aquí .

La igualdad

De lo anterior también se deduce que dos objetos nunca pueden ser iguales, incluso si tienen las mismas propiedades. Esto se debe al hecho de que JS, de hecho, compara la ubicación de los objetos en la memoria, y dos objetos nunca están en la misma celda de memoria.

 // Two distinct objects with the same properties are not equal var fruit = {name: 'apple'}; var fruitbear = {name: 'apple'}; fruit === fruitbear; // return false // here fruit and fruitbear are pointing to same object var fruit = {name: 'apple'}; var fruitbear = fruit; fruit === fruitbear; // return true 

Entonces, lo más probable es que ya se haya preguntado cómo comparar objetos o cómo realizar diversas manipulaciones con objetos, dado el requisito de su inmutabilidad.

Considere varias posibilidades.

Cambio de objeto

Supongamos que está claro que, en el buen sentido, no deberíamos cambiar los objetos, por lo que queremos crear una copia del objeto correspondiente y cambiar sus propiedades. Object.assign () viene al rescate .

 var obj = { a : 1, b : 2}; var newObj = Object.assign({}, obj,{a:2}) // {a : 2, b : 2 } 

Si queremos cambiar el valor de la propiedad a de obj , podemos usar object.assign para crear una copia de obj y cambiarlo.

El ejemplo muestra que primero creamos un objeto vacío, luego copiamos los valores obj y hacemos nuestros cambios, y finalmente obtenemos un objeto nuevo y listo para usar.

Tenga en cuenta que este método no funcionará para la copia profunda. Hablando de copia profunda, queremos decir que necesita copiar un objeto con una o más propiedades.

 const obj = {a : 1, b : { a : 1 } }; // b property is an object 

Object.assign () copia las propiedades del objeto, por lo que si el valor de la propiedad es un puntero a un objeto, solo se copia el puntero.

La copia profunda requiere una operación recursiva. Puede escribir una función aquí o simplemente usar el método _.cloneDeep de la biblioteca Lodash .

Comparación de objetos

Hay una forma genial de trabajar con objetos: la conversión de líneas. En el siguiente ejemplo, convertimos ambos objetos en cadenas y los comparamos:

 JSON.stringify(obj1) === JSON.stringify(obj2) 

Este enfoque está justificado, porque al final comparamos cadenas que representan un puntero a un tipo de valor. La mala noticia es que no siempre funciona, principalmente porque uno u otro orden de propiedades del objeto no está garantizado.

Otra buena solución es usar el método _.isEqual de Lodash , que realiza una comparación profunda de objetos.

Y antes de terminar, repasemos algunas preguntas frecuentes sobre los objetos. Esto ayudará a profundizar en el tema y poner en práctica los conocimientos adquiridos.

Intente pensar en la solución usted mismo antes de leer la respuesta.

¿Cómo averiguar la longitud de un objeto?


Para obtener la respuesta, es necesario ordenar todas las propiedades del objeto una por una y contarlas. Hay varias formas de hacer esta iteración:

  • para adentro . Este método cubre todas las propiedades contables de un objeto y su cadena prototipo. Nos familiarizamos con el prototipo (y, espero, aprendimos el material), por lo que debe quedar claro que el uso de for in no siempre será cierto para obtener las propiedades del objeto.
  • Object.keys . Este método devuelve una matriz con las claves de sus propias propiedades contables (que pertenecen al objeto especificado). Este enfoque es mejor, ya que solo trabajamos en las propiedades del objeto, sin recurrir a las propiedades del prototipo . Sin embargo, hay situaciones en las que establece el atributo enumerable de alguna propiedad en falso, y object.keys finalmente lo omite y obtiene un resultado incorrecto. Esto rara vez sucede, pero en tales casos getOwnPropertyNames será útil .
  • getOwnPropertyNames devuelve una matriz que contiene todas las claves propias del objeto (contables e incontables).

También vale la pena mencionar:

  • Object.values ​​itera sobre sus propias propiedades de conteo y devuelve una matriz con los valores correspondientes.
  • Object.entries itera sobre sus propias propiedades de conteo y devuelve una matriz con claves y sus valores .

Creo que notó que la mayoría de los métodos enumerados anteriormente devuelven una matriz. Esta es una oportunidad para aprovechar al máximo los métodos de JavaScript para trabajar con matrices.

Uno de estos métodos es array.length . Al final, solo podemos escribir

 let objLength = Object.getOwnPropertyNames(obj).length; 

¿Cómo verificar si un objeto está vacío?


  1. JSON.stringify (myObj) === "{}" . Aquí nuevamente utilizamos la herramienta de conversión de cadenas, que facilita verificar si un objeto está vacío (comparando cadenas, no objetos).
  2. ! Object.keys (myobj) .length // verdadero . Como mencioné, convertir las claves de un objeto en una matriz puede ser muy útil. Aquí usamos la longitud de propiedad conveniente heredada de Array.prototype , verificando con ella la longitud de las claves en la matriz. En JS, 0 se convierte en falso, ¡así que agrega ! Lo convertimos en verdad. Cualquier otro número se convertirá en falso.

En conclusión


Espero que ahora se sienta más seguro al crear objetos y trabajar con ellos. Resumamos:

  • Recuerde que los objetos pertenecen al tipo de referencia, lo que significa que se recomienda trabajar con ellos sin cambiar los objetos originales.
  • Haz amigos con la propiedad del prototipo y la cadena del prototipo .
  • Conozca las herramientas auxiliares para trabajar con objetos. Recuerde que puede convertir objetos en cadenas, obtener una matriz con sus claves o simplemente iterar sobre sus propiedades utilizando un conjunto de métodos que hemos conocido.

Buena suerte aprendiendo objetos JavaScript.

imagen

Source: https://habr.com/ru/post/es419193/


All Articles