Eu tenho uma estrutura de dados aninhada contendo objetos e matrizes. Como posso extrair as informações, ou seja, acessar valores (ou chaves) específicos ou múltiplos?
Por exemplo:
var data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
Como acessar name
o segundo item items
?
javascript
arrays
object
nested
data-manipulation
Felix Kling
fonte
fonte
Respostas:
Preliminares
JavaScript possui apenas um tipo de dados que pode conter vários valores: Objeto . Uma matriz é uma forma especial de objeto.
(Simples) Os objetos têm a forma
Matrizes têm o formato
Matrizes e objetos expõem uma
key -> value
estrutura. As chaves em uma matriz devem ser numéricas, enquanto qualquer sequência pode ser usada como chave nos objetos. Os pares de valores-chave também são chamados de "propriedades" .As propriedades podem ser acessadas usando a notação de ponto
ou notação de colchete , se o nome da propriedade não for um nome de identificador JavaScript válido [spec] ou se o nome for o valor de uma variável:
Por esse motivo, os elementos da matriz só podem ser acessados usando a notação de colchete:
Espere ... e o JSON?
JSON é uma representação textual de dados, assim como XML, YAML, CSV e outros. Para trabalhar com esses dados, primeiro é necessário convertê-los em tipos de dados JavaScript, como arrays e objetos (e como trabalhar com eles foi explicado). Como analisar JSON é explicado na pergunta Analisar JSON em JavaScript? .
Material de leitura adicional
Como acessar matrizes e objetos é um conhecimento fundamental do JavaScript e, portanto, é aconselhável ler o MDN JavaScript Guide , especialmente as seções
Acessando estruturas de dados aninhadas
Uma estrutura de dados aninhada é uma matriz ou objeto que se refere a outras matrizes ou objetos, ou seja, seus valores são matrizes ou objetos. Essas estruturas podem ser acessadas aplicando consecutivamente a notação de ponto ou colchete.
Aqui está um exemplo:
Vamos supor que queremos acessar
name
o segundo item.Aqui está como podemos fazer isso passo a passo:
Como podemos ver
data
é um objeto, portanto, podemos acessar suas propriedades usando a notação de pontos. Aitems
propriedade é acessada da seguinte forma:O valor é uma matriz, para acessar seu segundo elemento, precisamos usar a notação entre colchetes:
Este valor é um objeto e usamos a notação de ponto novamente para acessar a
name
propriedade. Por fim, obtemos:Como alternativa, poderíamos ter usado a notação de colchete para qualquer uma das propriedades, especialmente se o nome contivesse caracteres que o tornariam inválido para o uso da notação de ponto:
Estou tentando acessar uma propriedade, mas recebo apenas de
undefined
volta?Na maioria das vezes, quando você está recebendo
undefined
, o objeto / matriz simplesmente não possui uma propriedade com esse nome.Use
console.log
ouconsole.dir
inspecione a estrutura do objeto / matriz. A propriedade que você está tentando acessar pode estar realmente definida em um objeto / matriz aninhada.E se os nomes das propriedades forem dinâmicos e eu não os conhecermos de antemão?
Se os nomes das propriedades são desconhecidos ou queremos acessar todas as propriedades de um objeto / elementos de uma matriz, podemos usar o loop
for...in
[MDN] para objetos e o loopfor
[MDN] para matrizes para iterar todas as propriedades / elementos.Objetos
Para iterar sobre todas as propriedades de
data
, podemos iterar sobre o objeto da seguinte maneira:Dependendo da origem do objeto (e o que você deseja fazer), talvez seja necessário testar em cada iteração se a propriedade é realmente uma propriedade do objeto ou se é uma propriedade herdada. Você pode fazer isso com
Object#hasOwnProperty
[MDN] .Como alternativa para
for...in
comhasOwnProperty
, você pode usarObject.keys
[MDN] para obter uma variedade de nomes de propriedades :Matrizes
Para iterar sobre todos os elementos da
data.items
matriz , usamos umfor
loop:Também se poderia usar
for...in
para iterar sobre matrizes, mas há razões para que isso deva ser evitado: Por que 'for (var item da lista)' com matrizes consideradas más práticas em JavaScript? .Com o crescente suporte do ECMAScript 5 ao navegador, o método array
forEach
[MDN] também se torna uma alternativa interessante:Em ambientes que suportam o ES2015 (ES6), você também pode usar o loop [MDN] , que não só funciona para matrizes, mas também para qualquer iterável :
for...of
Em cada iteração,
for...of
nos fornece diretamente o próximo elemento do iterável, não há "índice" para acessar ou usar.E se a "profundidade" da estrutura de dados for desconhecida para mim?
Além das chaves desconhecidas, a "profundidade" da estrutura de dados (ou seja, quantos objetos aninhados) ela possui, também pode ser desconhecida. Como acessar propriedades profundamente aninhadas geralmente depende da estrutura de dados exata.
Mas se a estrutura de dados contiver padrões repetidos, por exemplo, a representação de uma árvore binária, a solução normalmente inclui o acesso recursivo [Wikipedia] a cada nível da estrutura de dados.
Aqui está um exemplo para obter o primeiro nó da folha de uma árvore binária:
Mostrar snippet de código
Uma maneira mais genérica de acessar uma estrutura de dados aninhada com chaves e profundidade desconhecidas é testar o tipo do valor e agir de acordo.
Aqui está um exemplo que adiciona todos os valores primitivos dentro de uma estrutura de dados aninhados a uma matriz (supondo que ela não contenha nenhuma função). Se encontrarmos um objeto (ou matriz), simplesmente chamaremos
toArray
novamente esse valor (chamada recursiva).Mostrar snippet de código
Ajudantes
Como a estrutura de um objeto ou matriz complexo não é necessariamente óbvia, podemos inspecionar o valor em cada etapa para decidir como avançar.
console.log
[MDN] econsole.dir
[MDN] nos ajudam a fazer isso. Por exemplo (saída do console do Chrome):Aqui vemos que essa
data.items
é uma matriz com dois elementos que são ambos objetos. No console do Chrome, os objetos podem ser expandidos e inspecionados imediatamente.Isso nos diz que
data.items[1]
é um objeto e, após expandi-lo, vemos que ele possui três propriedadesid
,name
e__proto__
. Esta última é uma propriedade interna usada para a cadeia de protótipos do objeto. A cadeia de protótipo e a herança estão fora do escopo desta resposta.fonte
let object = {a: 1, b: 2, c: { a: 3, b: 4 }};
, isso retorna uma matriz contendo uma matriz para cada objeto aninhado, nesse caso,[ 1, 2, [ 3, 4 ] ]
não seria melhor usar concat na chamada recursiva em vez de push? (exigindo resultado a ser mutável)Você pode acessá-lo desta maneira
ou
Ambas as formas são iguais.
fonte
Caso você esteja tentando acessar uma
item
estrutura de exemplo usandoid
ouname
, sem saber sua posição na matriz, a maneira mais fácil de fazer isso seria usar a biblioteca underscore.js :Pela minha experiência, o uso de funções de ordem superior em vez de
for
ou emfor..in
loop resulta em um código mais fácil de raciocinar e, portanto, mais sustentável.Apenas meus 2 centavos.
fonte
Objetos e matrizes tem muitos métodos internos que podem ajudá-lo no processamento de dados.
Nota: em muitos exemplos, estou usando funções de seta . Eles são semelhantes às expressões de função , mas vinculam o
this
valor lexicamente.Object.keys()
,Object.values()
(ES 2017) eObject.entries()
(ES 2017)Object.keys()
retorna uma matriz de chaves do objeto,Object.values()
retorna uma matriz de valores do objeto eObject.entries()
retorna uma matriz de chaves do objeto e valores correspondentes em um formato[key, value]
.Object.entries()
com um loop for-of e atribuição de desestruturaçãoÉ muito conveniente iterar o resultado
Object.entries()
com uma atribuição de loop for-of e desestruturação .O loop for-of permite iterar elementos da matriz. A sintaxe é
for (const element of array)
(podemos substituirconst
porvar
oulet
, mas é melhor usá-loconst
se não pretendemos modificarelement
).A atribuição de reestruturação permite extrair valores de uma matriz ou objeto e atribuí-los a variáveis. Nesse caso,
const [key, value]
significa que, em vez de atribuir a[key, value]
matriz aelement
, atribuímos o primeiro elemento dessa matriz akey
e o segundo elemento avalue
. É equivalente a isso:Como você pode ver, a desestruturação torna isso muito mais simples.
Array.prototype.every()
eArray.prototype.some()
O
every()
método retornarátrue
se a função de retorno de chamada especificada retornartrue
para todos os elementos da matriz. Osome()
método retornarátrue
se a função de retorno de chamada especificada retornartrue
para algum (pelo menos um) elemento.Array.prototype.find()
eArray.prototype.filter()
Os
find()
métodos retornam o primeiro elemento que satisfaz a função de retorno de chamada fornecida. Ofilter()
método retorna uma matriz de todos os elementos que satisfazem a função de retorno de chamada fornecida.Array.prototype.map()
O
map()
método retorna uma matriz com os resultados da chamada de uma função de retorno de chamada fornecida nos elementos da matriz.Array.prototype.reduce()
O
reduce()
método reduz uma matriz para um único valor chamando a função de retorno de chamada fornecida com dois elementos.O
reduce()
método usa um segundo parâmetro opcional, que é o valor inicial. Isso é útil quando a matriz que você chamareduce()
pode ter zero ou um elemento. Por exemplo, se quiséssemos criar uma funçãosum()
que pega uma matriz como argumento e retorna a soma de todos os elementos, poderíamos escrevê-la assim:fonte
Object.keys(data["items"]).forEach(function(key) { console.log(data["items"][key].id); console.log(data["items"][key].name); });
Às vezes, acessar um objeto aninhado usando uma string pode ser desejável. A abordagem simples é o primeiro nível, por exemplo
Mas esse geralmente não é o caso do json complexo. À medida que o json se torna mais complexo, as abordagens para encontrar valores dentro do json também se tornam complexas. É melhor uma abordagem recursiva para navegar no json, e como essa recursão é alavancada dependerá do tipo de dados que está sendo pesquisado. Se houver instruções condicionais envolvidas, uma pesquisa json pode ser uma boa ferramenta para usar.
Se a propriedade que está sendo acessada já for conhecida, mas o caminho for complexo, por exemplo, neste objeto
E você sabe que deseja obter o primeiro resultado da matriz no objeto, talvez você queira usar
No entanto, isso causará uma exceção, pois não há propriedade do objeto com esse nome. A solução para poder usar isso seria achatar o aspecto de árvore do objeto. Isso pode ser feito recursivamente.
Agora, o objeto complexo pode ser achatado
Aqui está uma
jsFiddle Demo
dessas abordagens sendo usadas.fonte
obj["arr[0].name"]
vez deobj.arr[0].name
? Você quase não precisa / deseja lidar com objetos achatados, exceto a serialização.Esta questão é bastante antiga, portanto, como uma atualização contemporânea. Com o início do ES2015, existem alternativas para obter os dados necessários. Agora existe um recurso chamado destruição de objeto para acessar objetos aninhados.
O exemplo acima cria uma variável chamada a
secondName
partir daname
chave a partir de uma matriz chamadaitems
, solitária,,
diz pular o primeiro objeto na matriz.Notavelmente, é provavelmente um exagero para este exemplo, pois o acesso simples à matriz é mais fácil de ler, mas é útil ao separar objetos em geral.
Essa é uma introdução muito breve ao seu caso de uso específico. A desestruturação pode ser uma sintaxe incomum para se acostumar primeiro. Eu recomendo a leitura da documentação de Destruição das Tarefas da Mozilla para saber mais.
fonte
Para acessar um atributo aninhado, é necessário especificar seu nome e, em seguida, procurar no objeto.
Se você já conhece o caminho exato, pode codificá-lo em seu script da seguinte maneira:
estes também funcionam -
Quando você não sabe o nome exato antes, ou um usuário é quem fornece o nome para você. É necessário pesquisar dinamicamente na estrutura de dados. Alguns sugeriram aqui que a pesquisa pode ser feita usando um
for
loop, mas existe uma maneira muito simples de percorrer um caminho usandoArray.reduce
.O caminho é uma maneira de dizer: Primeiro, pegue o objeto com a chave
items
, que por acaso é uma matriz. Em seguida, pegue o1
elemento -st (0 matrizes de índice). Por último, pegue o objeto com a chavename
nesse elemento da matriz, que passa a ser a stringbar
.Se você tem um caminho muito longo, pode até usar isso
String.split
para facilitar tudo isso -Isso é apenas JavaScript, sem o uso de bibliotecas de terceiros, como jQuery ou lodash.
fonte
ou
Basicamente, use um ponto entre cada descendente que se desdobra embaixo dele e quando você tiver nomes de objetos compostos por duas cadeias, use a notação ["obj Name"]. Caso contrário, apenas um ponto seria suficiente;
Fonte: https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-objects
para adicionar a isso, acessar matrizes aninhadas aconteceria da seguinte maneira:
Fonte: https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-arrays/
Outro documento mais útil que descreve a situação acima: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Basics#Bracket_notation
Acesso à propriedade via caminhada de pontos: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors#Dot_notation
fonte
Você poderia usar a
lodash _get
função:fonte
Usar JSONPath seria uma das soluções mais flexíveis se você estiver disposto a incluir uma biblioteca: https://github.com/s3u/JSONPath (nó e navegador)
Para o seu caso de uso, o caminho json seria:
tão:
fonte
Caso alguém esteja visitando esta pergunta em 2017 ou mais tarde e procurando uma maneira fácil de lembrar , aqui está uma publicação elaborada no blog Acessando Objetos Aninhados em JavaScript sem ser enganada por
Não é possível ler a propriedade 'foo' de erro indefinido
1. Padrão de acesso a objetos aninhados de Oliver Steele
A maneira mais fácil e limpa de usar o padrão de acesso a objetos aninhados de Oliver Steele
Com essa notação, você nunca encontrará
Não é possível ler a propriedade 'nome' de indefinido .
Você basicamente verifica se o usuário existe; caso contrário, você cria um objeto vazio em tempo real. Dessa forma, a chave do próximo nível sempre será acessada a partir de um objeto existente ou vazio , mas nunca indefinido.
2. Acesse objetos aninhados usando a matriz Reduzir
Para poder acessar matrizes aninhadas, você pode escrever seu próprio utilitário de redução de matriz.
Há também um excelente tipo de manipulação mínima de typy de biblioteca que faz tudo isso para você.
fonte
((user || {}).address || new Array(3))[1].name
...[1].bar
, resultaria em um erro se o elemento1
não existisse. Mas esse também é o caso,....foo.bar
sefoo
não existisse. Você também precisa "proteger" o acesso1
, assim como "protege" qualquer outro acesso à propriedade. Uma matriz é apenas um objeto. Um "elemento de matriz" é apenas uma propriedade. Aplicado corretamente, seria(((user || {}).address || {})[1] || {}).name
.Eu prefiro o JQuery. É mais limpo e fácil de ler.
fonte
Acessando dinamicamente objetos de vários níveis.
Violino de trabalho: https://jsfiddle.net/andreitodorut/3mws3kjL/
fonte
Se você estiver procurando por um ou mais objetos que atendam a certos critérios, você tem algumas opções usando query-js
Há também um
single
e um,singleOrDefault
eles funcionam muito bemfirst
efirstOrDefault
respectivamente. A única diferença é que eles jogarão se mais de uma partida for encontrada.para obter mais explicações sobre query-js, você pode começar com este post
fonte
The Underscore js Way
Que é uma biblioteca JavaScript que fornece toda uma bagunça de
functional programming
ajudantes úteis sem estender nenhum objeto interno.Solução:
fonte
Pergunta antiga, mas como ninguém mencionou lodash (apenas sublinhado).
Caso você já esteja usando o lodash em seu projeto, acho uma maneira elegante de fazer isso em um exemplo complexo:
Opt 1
igual a:
Opt 2
A diferença entre a primeira e a segunda opção é que, na Opção 1, se uma das propriedades estiver faltando (indefinida) no caminho, você não receberá um erro, ela retornará o terceiro parâmetro.
Para filtro de matriz lodash tem,
_.find()
mas eu prefiro usar o regularfilter()
. Mas ainda acho que o método acima_.get()
é super útil ao trabalhar com dados realmente complexos. Enfrentei no passado APIs realmente complexas e foi útil!Espero que possa ser útil para quem está procurando opções para manipular dados realmente complexos que o título implica.
fonte
Não acho que o questionador se refira apenas a um objeto aninhado de nível, por isso apresento a seguinte demonstração para demonstrar como acessar o nó do objeto json profundamente aninhado. Tudo bem, vamos encontrar o nó com o ID '5'.
fonte
Você pode usar a sintaxe
jsonObject.key
para acessar o valor. E se você deseja acessar um valor de uma matriz, pode usar a sintaxejsonObjectArray[index].key
.Aqui estão os exemplos de código para acessar vários valores e dar a você a ideia.
fonte
Abordagem dinâmica
Na
deep(data,key)
função abaixo , você pode usar umakey
seqüência arbitrária - no seu casoitems[1].name
(você pode usar a notação de matriz[i]
em qualquer nível) - se a chave for inválida, o valor indefinido será retornado.Mostrar snippet de código
fonte
Uma abordagem pitônica, recursiva e funcional para desvendar árvores JSON arbitrárias:
em que data é uma lista python (analisada a partir de uma sequência de texto JSON):
fonte
A função grep do jQuery permite filtrar através de uma matriz:
fonte
fonte
Em 2020, você pode usar o @ babel / plugin-proposta-opcional-encadeamento; é muito fácil acessar valores aninhados em um objeto.
https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining
https://github.com/tc39/proposal-optional-chaining
fonte
Minha
stringdata
está vindo do arquivo PHP, mas ainda assim, indico aqui emvar
. Quando eu levo meu json diretamente paraobj
ele, nada mostrará por isso que eu coloquei meu arquivo json comovar obj=JSON.parse(stringdata);
Então, depois que eu recebomessage
obj e mostro na caixa de alerta, recebodata
qual é o array json e armazeno em uma variável,ArrObj
então leio o primeiro objeto desse array com um valor-chave como esteArrObj[0].id
fonte
stringjson
não é uma string.Usar o lodash seria uma boa solução
Ex:
fonte