Mam zagnieżdżoną strukturę danych zawierającą obiekty i tablice. Jak mogę wyodrębnić informacje, tj. Uzyskać dostęp do określonej lub wielu wartości (lub kluczy)?
Na przykład:
var data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
Jak mogę uzyskać dostęp name
do drugiego elementu w items
?
javascript
arrays
object
nested
data-manipulation
Felix Kling
źródło
źródło
Odpowiedzi:
Czynności wstępne
JavaScript ma tylko jeden typ danych, który może zawierać wiele wartości: Object . Array jest specjalną formą obiektu.
(Zwykły) Obiekty mają formę
Tablice mają formę
Zarówno tablice, jak i obiekty ujawniają
key -> value
strukturę. Klucze w tablicy muszą być numeryczne, podczas gdy dowolny ciąg może być używany jako klucz w obiektach. Pary klucz-wartość są również nazywane „właściwościami” .Dostęp do właściwości można uzyskać za pomocą notacji kropkowej
lub notacja w nawiasach , jeśli nazwa właściwości nie byłaby prawidłową nazwą identyfikatora JavaScript [spec] lub nazwa jest wartością zmiennej:
Z tego powodu dostęp do elementów tablicy można uzyskać tylko za pomocą notacji w nawiasach:
Poczekaj ... a co z JSON?
JSON to tekstowa reprezentacja danych, podobnie jak XML, YAML, CSV i inne. Aby pracować z takimi danymi, należy najpierw przekonwertować je na typy danych JavaScript, tj. Tablice i obiekty (a właśnie wyjaśniono, jak z nimi pracować). Jak parsować JSON wyjaśniono w pytaniu Parse JSON w JavaScript? .
Dalsze materiały do czytania
Jak uzyskać dostęp do tablic i obiektów jest podstawową wiedzą o JavaScript, dlatego wskazane jest przeczytanie MDN JavaScript Guide , zwłaszcza sekcji
Dostęp do zagnieżdżonych struktur danych
Zagnieżdżona struktura danych to tablica lub obiekt, który odnosi się do innych tablic lub obiektów, tzn. Jego wartościami są tablice lub obiekty. Dostęp do takich struktur można uzyskać, stosując kolejno notację kropkową lub nawiasową.
Oto przykład:
Załóżmy, że chcemy uzyskać dostęp
name
do drugiego elementu.Oto jak możemy to zrobić krok po kroku:
Jak widzimy,
data
jest obiektem, dlatego możemy uzyskać dostęp do jego właściwości za pomocą notacji kropkowej.items
Nieruchomość jest dostępna w następujący sposób:Wartością jest tablica, aby uzyskać dostęp do jej drugiego elementu, musimy użyć notacji nawiasowej:
Ta wartość jest obiektem i ponownie używamy notacji kropkowej, aby uzyskać dostęp do
name
właściwości. W końcu otrzymujemy:Alternatywnie, moglibyśmy użyć notacji nawiasowej dla dowolnej właściwości, szczególnie jeśli nazwa zawierała znaki, które spowodowałyby, że byłaby niepoprawna dla użycia notacji kropkowej:
Próbuję uzyskać dostęp do nieruchomości, ale dostaję tylko z
undefined
powrotem?W większości przypadków
undefined
obiekt / tablica po prostu nie ma właściwości o tej nazwie.Użyj
console.log
lubconsole.dir
i sprawdź strukturę obiektu / tablicy. Właściwość, do której próbujesz uzyskać dostęp, może być faktycznie zdefiniowana w zagnieżdżonym obiekcie / tablicy.Co się stanie, jeśli nazwy właściwości są dynamiczne i nie znam ich wcześniej?
Jeśli nazwy właściwości są nieznane lub chcemy uzyskać dostęp do wszystkich właściwości obiektu / elementów tablicy, możemy użyć pętli
for...in
[MDN] dla obiektów i pętlifor
[MDN] dla tablic, aby iterować wszystkie właściwości / elementy.Obiekty
Aby iterować po wszystkich właściwościach
data
, możemy iterować po obiekcie w następujący sposób:W zależności od tego, skąd pochodzi obiekt (i co chcesz zrobić), w każdej iteracji może być konieczne sprawdzenie, czy właściwość jest rzeczywiście własnością obiektu, czy jest dziedziczoną właściwością. Możesz to zrobić za pomocą
Object#hasOwnProperty
[MDN] .Alternatywnie do
for...in
zhasOwnProperty
można użyćObject.keys
[MDN], aby uzyskać tablicę nazw właściwości :Tablice
Aby wykonać iterację po wszystkich elementach
data.items
tablicy , używamyfor
pętli:Można również użyć
for...in
do iteracji po tablicach, ale istnieją powody, dla których należy tego unikać: Dlaczego „for (var item in list)” z tablicami jest uważane za złą praktykę w JavaScript? .Wraz z rosnącą obsługą przeglądarki ECMAScript 5 metoda tablicowa
forEach
[MDN] staje się również interesującą alternatywą:W środowiskach obsługujących ES2015 (ES6) można również użyć pętli [MDN] , która działa nie tylko dla tablic, ale dla każdej iterowalnej :
for...of
W każdej iteracji
for...of
bezpośrednio daje nam kolejny element iteracji, nie ma „indeksu”, do którego można by uzyskać dostęp lub z którego można by korzystać.Co jeśli „głębia” struktury danych jest mi nieznana?
Oprócz nieznanych kluczy „głębia” struktury danych (tj. Ile ma zagnieżdżonych obiektów), może być również nieznana. Sposób uzyskiwania dostępu do głęboko zagnieżdżonych właściwości zwykle zależy od dokładnej struktury danych.
Ale jeśli struktura danych zawiera powtarzające się wzorce, np. Reprezentację drzewa binarnego, rozwiązanie zazwyczaj obejmuje rekursywny dostęp [Wikipedia] do każdego poziomu struktury danych.
Oto przykład, aby uzyskać pierwszy węzeł liścia drzewa binarnego:
Pokaż fragment kodu
Bardziej ogólnym sposobem uzyskania dostępu do zagnieżdżonej struktury danych z nieznanymi kluczami i głębokością jest przetestowanie typu wartości i odpowiednie działanie.
Oto przykład, który dodaje wszystkie pierwotne wartości w zagnieżdżonej strukturze danych do tablicy (zakładając, że nie zawiera żadnych funkcji). Jeśli napotkamy obiekt (lub tablicę), po prostu wywołujemy
toArray
ponownie tę wartość (wywołanie rekurencyjne).Pokaż fragment kodu
Pomocnicy
Ponieważ struktura złożonego obiektu lub tablicy niekoniecznie jest oczywista, możemy sprawdzić wartość na każdym kroku, aby zdecydować, jak przejść dalej.
console.log
[MDN] iconsole.dir
[MDN] pomagają nam to zrobić. Na przykład (dane wyjściowe konsoli Chrome):Widzimy tutaj, że
data.items
jest to tablica z dwoma elementami, które są obiektami. W konsoli Chrome obiekty mogą być nawet powiększane i sprawdzane natychmiast.To mówi nam, że
data.items[1]
jest to obiekt, a po rozwinięciu widzimy, że ma on trzy właściwościid
,name
oraz__proto__
. Ta ostatnia jest wewnętrzną właściwością stosowaną w łańcuchu prototypów obiektu. Jednak łańcuch prototypów i dziedziczenie nie mieszczą się w tej odpowiedzi.źródło
let object = {a: 1, b: 2, c: { a: 3, b: 4 }};
, zwraca tablicę zawierającą tablicę dla każdego zagnieżdżonego obiektu, w tym przypadku[ 1, 2, [ 3, 4 ] ]
Czy nie byłoby lepiej używać konkatii w wywołaniu rekurencyjnym zamiast wypychania? (wymagający zmiany wyniku)Możesz uzyskać do niego dostęp w ten sposób
lub
Oba sposoby są równe.
źródło
W przypadku, gdy próbujesz uzyskać dostęp
item
do przykładowej struktury za pomocąid
lubname
, nie znając jej pozycji w tablicy, najłatwiejszym sposobem jest skorzystanie z biblioteki underscore.js :Z mojego doświadczenia wynika, że używanie funkcji wyższego rzędu zamiast
for
lubfor..in
pętli powoduje, że kod jest łatwiejszy do zrozumienia, a zatem łatwiejszy w utrzymaniu.Tylko moje 2 centy.
źródło
Obiekty i tablice mają wiele wbudowanych metod, które mogą pomóc w przetwarzaniu danych.
Uwaga: w wielu przykładach używam funkcji strzałek . Są podobne do wyrażeń funkcyjnych , ale wiążą
this
wartość leksykalnie.Object.keys()
,Object.values()
(ES 2017) iObject.entries()
(ES 2017)Object.keys()
zwraca tablicę kluczy obiektu,Object.values()
zwraca tablicę wartości obiektu iObject.entries()
zwraca tablicę kluczy obiektu i odpowiadających im wartości w formacie[key, value]
.Object.entries()
z pętlą for-of i destrukcjąBardzo wygodnie jest iterować wynik
Object.entries()
za pomocą pętli for-of i destrukcji .Pętla For-of pozwala na iterację elementów tablicy. Składnia jest następująca
for (const element of array)
(możemy zastąpićconst
zvar
albolet
, ale lepiej do użytkuconst
, jeśli nie zamierzamy modyfikowaćelement
).Przypisanie destrukcyjne pozwala wyodrębnić wartości z tablicy lub obiektu i przypisać je do zmiennych. W tym przypadku
const [key, value]
oznacza, że zamiast przypisywać[key, value]
tablicę doelement
, przypisujemy pierwszy element tej tablicy do,key
a drugi element dovalue
. Jest to równoważne z tym:Jak widać, restrukturyzacja sprawia, że jest to o wiele prostsze.
Array.prototype.every()
iArray.prototype.some()
Te
every()
metody powracatrue
jeśli określony powraca funkcję wywołania zwrotnegotrue
dla każdego elementu macierzy. Tesome()
metody powracatrue
Jeśli określona funkcja zwraca zwrotnatrue
do pewnego (co najmniej jeden) elementu.Array.prototype.find()
iArray.prototype.filter()
Te
find()
metody zwraca się pierwszy element, który spełnia podane funkcję wywołania zwrotnego.filter()
Sposób powraca tablicy wszystkie elementy, które spełnia podaną funkcję wywołania zwrotnego.Array.prototype.map()
map()
Zwraca tablicę z wynikami wywołanej podaną funkcję wywołania zwrotnego elementów macierzy.Array.prototype.reduce()
reduce()
Sposób zmniejsza tablicę do pojedynczej wartości wywołując podaną funkcję wywołania zwrotnego z dwóch elementów.reduce()
Sposobie, opcjonalny drugi parametr, który jest wartość początkowa. Jest to przydatne, gdy tablica, do której wywołujesz,reduce()
może zawierać zero lub jeden element. Na przykład, jeśli chcielibyśmy stworzyć funkcję,sum()
która przyjmuje tablicę jako argument i zwraca sumę wszystkich elementów, moglibyśmy zapisać to w ten sposób:źródło
Object.keys(data["items"]).forEach(function(key) { console.log(data["items"][key].id); console.log(data["items"][key].name); });
Czasami pożądany może być dostęp do zagnieżdżonego obiektu za pomocą łańcucha. Na przykład proste podejście to pierwszy poziom
Ale często nie jest tak w przypadku złożonego jsona. W miarę jak Json staje się bardziej złożony, podejścia do znajdowania wartości wewnątrz JSON również stają się złożone. Najlepsze jest rekurencyjne podejście do nawigacji w Json, a sposób wykorzystania tej rekurencji będzie zależeć od typu poszukiwanych danych. Jeśli w grę wchodzą instrukcje warunkowe, dobrym narzędziem może być wyszukiwanie w json .
Jeśli dostęp do właściwości jest już znany, ale ścieżka jest złożona, na przykład w tym obiekcie
I wiesz, że chcesz uzyskać pierwszy wynik tablicy w obiekcie, być może chciałbyś użyć
Spowoduje to jednak wyjątek, ponieważ nie ma właściwości obiektu o tej nazwie. Rozwiązaniem, które mogłoby to wykorzystać, byłoby spłaszczenie drzewnego aspektu obiektu. Można to zrobić rekurencyjnie.
Teraz złożony obiekt można spłaszczyć
Oto jedno
jsFiddle Demo
z takich podejść.źródło
obj["arr[0].name"]
zamiastobj.arr[0].name
? Prawie nie potrzebujesz / nie chcesz zajmować się spłaszczonymi obiektami, z wyjątkiem serializacji.To pytanie jest dość stare, więc stanowi współczesną aktualizację. Wraz z nadejściem ES2015 istnieją alternatywy, aby uzyskać potrzebne dane. Dostępna jest teraz funkcja zwana destrukcją obiektów w celu uzyskania dostępu do zagnieżdżonych obiektów.
Powyższy przykład tworzy zmienną wywoływaną
secondName
zname
klucza z tablicy o nazwieitems
, samotny,
mówi pominąć pierwszy obiekt w tablicy.W tym przypadku jest to prawdopodobnie przesada, ponieważ prosty dostęp do tablicy jest łatwiejszy do odczytania, ale przydaje się przy dzieleniu obiektów w ogóle.
To jest bardzo krótkie wprowadzenie do konkretnego przypadku użycia, na początku destrukcja może być niezwykłą składnią. Polecam przeczytanie dokumentacji Mozilli dotyczącej Destrukturyzacji, aby dowiedzieć się więcej.
źródło
Aby uzyskać dostęp do zagnieżdżonego atrybutu, musisz podać jego nazwę, a następnie przeszukać obiekt.
Jeśli znasz już dokładną ścieżkę, możesz ją na stałe zakodować w skrypcie:
te również działają -
Gdy nie znasz dokładnie dokładnej nazwy, lub użytkownik jest tym, który podaje nazwę dla Ciebie. Następnie wymagane jest dynamiczne przeszukiwanie struktury danych. Niektórzy sugerowali tutaj, że wyszukiwania można dokonać za pomocą
for
pętli, ale istnieje bardzo prosty sposób na przejście przez ścieżkęArray.reduce
.Ścieżka jest sposobem na powiedzenie: Najpierw weź obiekt za pomocą klucza
items
, którym jest tablica. Następnie weź1
element -st (0 tablic indeksu). Na koniec weź obiekt z kluczemname
w tym elemencie tablicy, którym jest ciąg znakówbar
.Jeśli masz bardzo długą ścieżkę, możesz nawet
String.split
ułatwić to wszystko -To jest po prostu JavaScript, bez użycia bibliotek stron trzecich, takich jak jQuery lub lodash.
źródło
lub
Zasadniczo użyj kropki między każdym potomkiem, który rozwija się pod nim, a gdy masz nazwy obiektów złożone z dwóch ciągów znaków, musisz użyć notacji [„obj name”]. W przeciwnym razie wystarczy kropka;
Źródło: https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-objects
aby to dodać, dostęp do zagnieżdżonych tablic wyglądałby tak:
Źródło: https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-arrays/
Kolejny bardziej przydatny dokument opisujący powyższą sytuację: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Basics#Bracket_notation
Dostęp do nieruchomości za pośrednictwem dot walking: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors#Dot_notation
źródło
Możesz użyć
lodash _get
funkcji:źródło
Użycie JSONPath byłoby jednym z najbardziej elastycznych rozwiązań, jeśli chcesz dołączyć bibliotekę: https://github.com/s3u/JSONPath (węzeł i przeglądarka)
W twoim przypadku ścieżka json to:
więc:
źródło
Na wszelki wypadek, gdy ktoś odwiedza to pytanie w 2017 roku lub później i szuka łatwego do zapamiętania sposobu, oto skomplikowany post na blogu na temat uzyskiwania dostępu do obiektów zagnieżdżonych w JavaScript bez przeszkadzania przez
Nie można odczytać właściwości „foo” niezdefiniowanego błędu
1. Wzorzec dostępu do zagnieżdżonych obiektów Olivera Steele
Najłatwiejszym i najczystszym sposobem jest użycie wzoru dostępu do zagnieżdżonych obiektów Olivera Steele
Dzięki tej notacji nigdy się nie spotkasz
Nie można odczytać właściwości „name” niezdefiniowanej .
Zasadniczo sprawdzasz, czy użytkownik istnieje, jeśli nie, tworzysz pusty obiekt w locie. W ten sposób dostęp do klucza następnego poziomu będzie zawsze możliwy z istniejącego obiektu lub pustego obiektu , ale nigdy z nieokreślonego.
2. Uzyskaj dostęp do zagnieżdżonych obiektów za pomocą funkcji Array Reduce
Aby mieć dostęp do zagnieżdżonych tablic, możesz napisać własną tablicę, zmniejsz wykorzystanie.
Istnieje również doskonały typ obsługujący minimalne typy bibliotek, który robi to wszystko za Ciebie.
źródło
((user || {}).address || new Array(3))[1].name
...[1].bar
spowodowałby błąd, gdyby element1
nie istniał. Ale tak jest również w przypadku,....foo.bar
gdybyfoo
nie istniało. Musisz również „strzec” dostępu1
, tak jak „strzeżesz” każdego innego dostępu do nieruchomości. Tablica jest tylko obiektem. „Element tablicy” to tylko własność. Byłoby to właściwie zastosowane(((user || {}).address || {})[1] || {}).name
.Wolę JQuery. Jest czystszy i łatwy do odczytania.
źródło
Dostęp do dynamicznie wielopoziomowego obiektu.
Działające skrzypce: https://jsfiddle.net/andreitodorut/3mws3kjL/
źródło
Jeśli szukasz jednego lub więcej obiektów spełniających określone kryteria, masz kilka opcji za pomocą zapytania-js
Są też
single
i a,singleOrDefault
które działają podobnie jakfirst
ifirstOrDefault
odpowiednio. Jedyną różnicą jest to, że rzucą, jeśli znaleziono więcej niż jedno dopasowanie.dla dalszego wyjaśnienia zapytania-js możesz zacząć od tego postu
źródło
The Underscore js Way
Która jest biblioteką JavaScript, która zapewnia cały bałagan przydatnych
functional programming
pomocników bez rozszerzania jakichkolwiek wbudowanych obiektów.Rozwiązanie:
źródło
Stare pytanie, ale jak nikt nie wspomniał o lodash (tylko podkreślenie).
Jeśli używasz już lodash w swoim projekcie, myślę, że jest to elegancki sposób w złożonym przykładzie:
Wybierz 1
taki sam jak:
Wybierz 2
Różnica między pierwszą a drugą opcją polega na tym, że w Opcji 1, jeśli brakuje jednej z właściwości (niezdefiniowanej) na ścieżce, nie pojawia się błąd, zwraca trzeci parametr.
W przypadku filtru tablicowego lodash ma,
_.find()
ale wolałbym używać zwykłegofilter()
. Ale nadal myślę o powyższej metodzie_.get()
jest bardzo przydatna podczas pracy z naprawdę złożonymi danymi. W przeszłości miałem do czynienia z bardzo złożonymi interfejsami API i było to przydatne!Mam nadzieję, że może być przydatny dla osób, które szukają opcji manipulowania naprawdę złożonymi danymi, które sugeruje tytuł.
źródło
Nie sądzę, by pytający dotyczył tylko jednego zagnieżdżonego poziomu, dlatego przedstawiam poniższe demo, aby pokazać, jak uzyskać dostęp do węzła głęboko zagnieżdżonego obiektu Json. W porządku, znajdźmy węzeł o identyfikatorze „5”.
źródło
Możesz użyć składni,
jsonObject.key
aby uzyskać dostęp do wartości. A jeśli chcesz uzyskać dostęp do wartości z tablicy, możesz użyć składnijsonObjectArray[index].key
.Oto przykłady kodu, aby uzyskać dostęp do różnych wartości, aby dać ci pomysł.
źródło
Podejście dynamiczne
W poniższej
deep(data,key)
funkcji możesz użyć dowolnegokey
ciągu znaków - w twoim przypadkuitems[1].name
(możesz użyć notacji tablicowej[i]
na dowolnym poziomie) - jeśli klucz jest nieprawidłowy, wówczas niezdefiniowany jest return.Pokaż fragment kodu
źródło
Pythoniczne, rekurencyjne i funkcjonalne podejście do rozwiązywania dowolnych drzew JSON:
gdzie dane to lista python (parsowana z ciągu tekstowego JSON):
źródło
Funkcja grep jQuery pozwala filtrować przez tablicę:
źródło
źródło
W 2020 roku możesz użyć @ babel / plugin-wniosek-opcjonalne-łączenie w łańcuchy, dostęp do zagnieżdżonych wartości w obiekcie jest bardzo łatwy.
https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining
https://github.com/tc39/proposal-optional-chaining
źródło
Mój
stringdata
pochodzi z pliku PHP, ale nadal wskazuję tutajvar
. Kiedy bezpośrednio wezmę doobj
niego swojego jsona , nic nie pokaże, dlatego umieściłem mój plik json jakovar obj=JSON.parse(stringdata);
więc po tym dostajęmessage
obj i wyświetlam w polu alertu, a następnie otrzymuję,data
która jest tablicą json i przechowuję w jednej zmiennej,ArrObj
a następnie czytam pierwszy obiekt tej tablicy o kluczowej wartości takiej jak taArrObj[0].id
źródło
stringjson
nie jest łańcuchem.Dobrym rozwiązaniem byłoby użycie lodash
Dawny:
źródło