Lidamos com objetos em JavaScript

Neste artigo, o autor, um desenvolvedor front-end, forneceu uma visão geral das principais maneiras de criar, modificar e comparar objetos JavaScript.


Objetos são um dos conceitos básicos em JavaScript. Quando comecei a estudá-los, eles pareciam bastante simples para mim: apenas algumas chaves e valores, conforme descrito na teoria.

Só depois de algum tempo comecei a perceber que o assunto é muito mais complicado do que eu pensava. E então eu comecei a estudar informações de várias fontes. Alguns deles deram uma boa idéia sobre o assunto, mas eu não pude ver imediatamente o quadro todo.

Neste post, tentei abordar todos os aspectos do trabalho com objetos em JS, sem me aprofundar nos detalhes individuais, mas sem perder detalhes importantes que ajudarão você a entender o assunto e a se sentir mais confiante durante o estudo.

Então, vamos começar com o básico.

Object


Um objeto em JavaScript é simplesmente uma coleção de propriedades, cada uma das quais é um par de valores-chave. As chaves podem ser acessadas usando a notação pontilhada ( obj.a ) ou entre colchetes ( obj ['a'] ).

Lembre-se de que colchetes devem ser usados ​​se a chave for:

  • não é um identificador JavaScript válido (ele tem um espaço, um traço, começa com um número ...)
  • é uma variável

Uma das propriedades que os objetos em JS obtêm quando são criados é chamada Prototype , e esse é um conceito muito importante.

Protótipo


Todo objeto em JavaScript possui uma propriedade interna chamada Prototype . Na maioria dos navegadores, você pode consultá-lo com a designação __proto__ .

Prototype é uma maneira de fornecer herança de propriedade em JavaScript. Assim, você pode compartilhar a funcionalidade sem duplicar o código na memória. O método funciona criando um relacionamento entre dois objetos.

Simplificando, o Prototype cria um ponteiro de um objeto para outro.

Cadeia de protótipo

Sempre que JS procura uma propriedade no objeto e não a encontra diretamente no próprio objeto, ele verifica a presença da propriedade no objeto protótipo. Se não houver nenhuma propriedade, o JS continuará pesquisando no protótipo do objeto relacionado. Isso continuará até que o JS encontre uma propriedade adequada ou atinja o final da cadeia.

Vejamos um exemplo:

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

contras é um construtor (apenas uma função que pode ser chamada usando o novo operador).

Na quinta linha, criamos um novo objeto - uma nova cópia de contras . Imediatamente após a criação, obj também obtém uma propriedade prototype.

E agora adicionamos propriedades ( 'b', 'c' ) ao protótipo do objeto contras .
Considere obj :

obj.a // 1 - tudo é como antes , obj.a ainda é 1.
obj.c - obj não tem propriedade c ! No entanto, como mencionado anteriormente, o JS agora o procurará no protótipo obj e retornará um valor de 4.

Agora, vamos pensar sobre qual é o valor do obj.b e qual será o seu valor quando removermos o obj.b ?

Obj.b é 2. Atribuímos a propriedade b , mas fizemos isso para o protótipo de contras , portanto, quando verificamos o obj.b , ainda obtemos 2. No entanto, imediatamente após a exclusão do obj.b, o JS não poderá mais encontrar b em o bj e, portanto, continuará a pesquisa no protótipo e retornará o valor 3.

Em seguida, quero falar brevemente sobre várias maneiras de criar um objeto e um pouco mais sobre protótipos.

Criação de Objetos


Literal do objeto: let obj = {a: 1};
Criamos um objeto com a seguinte cadeia de protótipos: obj ---> Object.prototype ---> null
Como você pode imaginar, object.prototype é o protótipo do objeto, assim como o fim da cadeia de protótipos.

Object.create (): var newObj = Object.create (obj);
NewObj terá a seguinte cadeia de protótipos: newObj ---> obj ---> Object.prototype ---> null

Construtor. Como no exemplo acima, o construtor é apenas uma função JS que nos permite usar o novo operador para criar novas instâncias.

Classes 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 é uma instância do construtor retângulo e, portanto, podemos chamar square.getArea () // 4 , square.width , bem como todas as funções herdadas de object.prototype .

Qual método é melhor? Se você planeja criar várias instâncias, poderá usar o ES6 ou o construtor. Se você planeja criar um objeto uma vez, é melhor especificar um literal, pois essa é a maneira mais fácil.

E agora, quando aprendemos sobre o protótipo e nos familiarizamos com todas as maneiras de criar novos objetos, podemos discutir um dos aspectos mais confusos associados aos objetos.

Comparando e Modificando Objetos


Em JavaScript, os objetos são do tipo de referência

Quando criamos um objeto, deixe obj = {a: 1}; , a variável obj obtém o endereço na memória do objeto, mas não seu valor! É imperativo entender essa diferença, pois erros podem ocorrer de outra maneira. Quando criamos outro objeto, deixe newObj = obj , na verdade criamos um ponteiro para uma determinada área da memória obj , e não um objeto completamente novo.

Isso significa que, ao executar newObj.a = 2 , na verdade alteramos obj para que obj.a se torne 2!

Essa abordagem leva facilmente ao aparecimento de bugs; muitas empresas trabalham com objetos imutáveis. Em vez de alterar um objeto já criado, você precisará novamente criar um novo objeto (uma cópia do original) e fazer alterações nele. É assim que as bibliotecas importantes, como o Redux, funcionam, e no geral esse é um dos conceitos básicos da programação funcional. Leia mais aqui .

Igualdade

Do exposto acima, também se segue que dois objetos nunca podem ser iguais, mesmo que tenham as mesmas propriedades. Isso ocorre porque o JS de fato compara a localização dos objetos na memória e dois objetos nunca estão na mesma célula de memória.

 // 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 

Portanto, você provavelmente já se perguntou como comparar objetos ou como executar várias manipulações com objetos, considerando o requisito de sua imutabilidade.

Considere algumas possibilidades.

Mudança de objeto

Suponha que esteja claro que, de uma maneira boa, não devemos mudar objetos, por isso queremos criar uma cópia do objeto correspondente e alterar suas propriedades. Object.assign () vem para o resgate .

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

Se quisermos alterar o valor da propriedade a de obj , podemos usar object.assign para criar uma cópia de obj e alterá-la.

O exemplo mostra que primeiro criamos um objeto vazio, copiamos os valores do objeto e fazemos nossas alterações, obtendo um objeto novo e pronto para o uso.

Observe que esse método não funcionará para cópias profundas. Falando em cópia profunda, queremos dizer que você precisa copiar um objeto com uma ou mais propriedades.

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

Object.assign () copia as propriedades do objeto; portanto, se o valor da propriedade for um ponteiro para um objeto, apenas o ponteiro será copiado.

A cópia profunda requer uma operação recursiva. Você pode escrever uma função aqui ou simplesmente usar o método _.cloneDeep da biblioteca Lodash .

Comparação de Objetos

Existe uma maneira legal de trabalhar com objetos - conversão de linha. No exemplo a seguir, convertemos os dois objetos em seqüências de caracteres e os comparamos:

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

Essa abordagem é justificada, porque, no final, comparamos cadeias que representam um ponteiro para um tipo de valor. A má notícia é que nem sempre funciona, principalmente porque uma ou outra ordem de propriedades do objeto não é garantida.

Outra boa solução é usar o método _.isEqual da Lodash , que realiza uma comparação profunda de objetos.

E antes de terminarmos, vamos examinar algumas perguntas frequentes sobre objetos. Isso ajudará a aprofundar o assunto e a colocar em prática o conhecimento adquirido.

Tente pensar na solução antes de ler a resposta.

Como descobrir o comprimento de um objeto?


Para obter a resposta, é necessário classificar todas as propriedades do objeto uma por uma e contá-las. Existem várias maneiras de fazer essa iteração:

  • para dentro Este método abrange todas as propriedades contáveis ​​de um objeto e sua cadeia de protótipos. Nós nos familiarizamos com o protótipo (e, espero, aprendemos o material), portanto, deve ficar claro que o uso de for in nem sempre será verdadeiro para obter as propriedades do objeto.
  • Object.keys . Este método retorna uma matriz com as chaves de todas as suas próprias propriedades contáveis (pertencentes ao objeto especificado). Essa abordagem é melhor, pois trabalhamos apenas nas propriedades do objeto, sem recorrer às propriedades do protótipo . No entanto, há situações em que você define o atributo enumerável de alguma propriedade como false e object.keys eventualmente o ignora e você obtém um resultado incorreto. Isso raramente acontece, mas nesses casos, getOwnPropertyNames será útil .
  • getOwnPropertyNames retorna uma matriz contendo todas as chaves do próprio objeto (contáveis ​​e incontáveis).

Também vale mencionar:

  • Object.values ​​itera sobre suas próprias propriedades de contagem e retorna uma matriz com os valores correspondentes.
  • Object.entries itera sobre suas próprias propriedades de contagem e retorna uma matriz com chaves e seus valores .

Eu acho que você percebeu que a maioria dos métodos listados acima retorna uma matriz. Esta é uma oportunidade de aproveitar ao máximo os métodos JavaScript para trabalhar com matrizes.

Um desses métodos é o array.length . No final, podemos apenas escrever

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

Como verificar se um objeto está vazio?


  1. JSON.stringify (myObj) === "{}" . Aqui, novamente, usamos a ferramenta de conversão de strings, que facilita verificar se um objeto está vazio (comparando strings, não objetos).
  2. ! Object.keys (myobj) .length // true . Como mencionei, converter as chaves de um objeto em uma matriz pode ser muito útil. Aqui usamos o conveniente tamanho da propriedade herdado de Array.prototype , verificando com ele o comprimento das chaves na matriz. Em JS, 0 passa a falso, então adicionando ! nós transformamos isso em verdade. Quaisquer outros números se tornarão falsos.

Em conclusão


Espero que agora você se sinta mais confiante ao criar objetos e trabalhar com eles. Vamos resumir:

  • Lembre-se de que os objetos pertencem ao tipo de referência, o que significa que é recomendável trabalhar com eles sem alterar os objetos originais.
  • Faça amizade com a propriedade protótipo e a cadeia de protótipos .
  • Conheça as ferramentas auxiliares no trabalho com objetos. Lembre-se de que você pode transformar objetos em seqüências de caracteres, obter uma matriz com suas chaves ou simplesmente iterar suas propriedades usando um conjunto de métodos que conhecemos.

Boa sorte para aprender objetos JavaScript.

imagem

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


All Articles