Jak Mogę uzyskać dostęp i przetwarzać zagnieżdżone obiekty, tablice lub JSON?

Mam zagnieżdżoną strukturę danych zawierającą obiekty i tablice. Jak wyodrębnić informacje, tj. uzyskać dostęp do określonych 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 do name drugiego elementu w items?

Author: Kamil Kiełczewski, 2012-08-12

27 answers

Eliminacje

JavaScript ma tylko jeden typ danych, który może zawierać wiele wartości: Object. Tablica jest specjalną formą obiektu.

(zwykły) obiekty mają postać

{key: value, key: value, ...}

Tablice mają postać

[value, value, ...]

Zarówno tablice, jak i Obiekty eksponują strukturę key -> value. Klucze w tablicy muszą być liczbowe, podczas gdy każdy łańcuch może być użyty jako klucz w obiektach. Pary klucz-wartość nazywane są również "właściwości" .

Właściwości można uzyskać za pomocą notacji kropkowej

const value = obj.someProperty;

Lub notacja w nawiasie , jeśli nazwa właściwości nie byłaby poprawną nazwą identyfikatora JavaScript [ spec], lub nazwa jest wartością zmiennej:

// the space is not a valid character in identifier names
const value = obj["some Property"];

// property name as variable
const name = "some Property";
const value = obj[name];
Z tego powodu elementy tablicy mogą być dostępne tylko przy użyciu notacji nawiasowej:]}
const value = arr[5]; // arr.5 would be a syntax error

// property name / index as variable
const x = 5;
const value = arr[x];
Czekaj... a co z JSONEM?

JSON jest reprezentacją tekstową danych, podobnie jak XML, YAML, CSV i inne. Aby pracować z takimi danymi, należy je najpierw przekonwertować na typy danych JavaScript, czyli tablice i Obiekty (a jak pracować z nimi właśnie wyjaśniono). Jak parsować JSON jest wyjaśnione w pytaniu parsować JSON w JavaScript? .

Dalszy materiał do czytania

Jak uzyskać dostęp do tablic i obiektów jest podstawową wiedzą JavaScript i dlatego wskazane jest przeczytanie MDN JavaScript Guide , szczególnie sekcje



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. jej wartości są tablicami lub obiektami. Do takich struktur można uzyskać dostęp, stosując kolejno notację kropkową lub nawiasową.

Oto przykład:

const data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

Załóżmy, że chcemy uzyskać dostęp do name drugiego elementu.

Oto jak możemy to zrobić krok po kroku:

Jak widzimy data jest obiektem, stąd możemy uzyskać dostęp do jego właściwości za pomocą notacji kropkowej. Dostęp do właściwości items jest następujący:

data.items
Wartość jest tablicą, aby uzyskać dostęp do jej drugiego elementu, musimy użyć notacji nawiasowej:
data.items[1]

Ta wartość jest obiektem i ponownie używamy notacji kropkowej, aby uzyskać dostęp do name własność. Więc w końcu otrzymujemy:

const item_name = data.items[1].name;

Alternatywnie, mogliśmy użyć notacji nawiasowej dla dowolnej właściwości, zwłaszcza jeśli nazwa zawierała znaki, które uczyniły ją nieważną dla użycia notacji kropkowej:

const item_name = data['items'][1]['name'];

Próbuję uzyskać dostęp do nieruchomości, ale odzyskuję tylko undefined?

Przez większość czasu, gdy otrzymujesz undefined, obiekt/tablica po prostu nie ma właściwości o tej nazwie.

const foo = {bar: {baz: 42}};
console.log(foo.baz); // undefined

Użycie console.log lub console.dir i sprawdzić strukturę obiektu / tablicy. Właściwość, do której próbujesz uzyskać dostęp, może być rzeczywiście zdefiniowana na zagnieżdżonym obiekcie / tablicy.

console.log(foo.bar.baz); // 42

Co 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ć for...in [MDN] pętla dla obiektów i for [MDN] pętla dla tablic do iteracji nad wszystkimi właściwościami / elementami.

Obiekty

Aby iterować nad wszystkimi właściwościami data, możemy iterować nad obiektem w następujący sposób:

for (const prop in data) {
    // `prop` contains the name of each property, i.e. `'code'` or `'items'`
    // consequently, `data[prop]` refers to the value of each property, i.e.
    // either `42` or the array
}

W zależności od tego, skąd pochodzi obiekt (i co chcesz zrobić), może być konieczne sprawdzenie w każdej iteracji, czy właściwość jest rzeczywiście własnością obiektu, czy jest dziedziczona. Możesz to zrobić z Object#hasOwnProperty [MDN].

Jako alternatywę dla for...in Z hasOwnProperty, możesz użyć Object.keys [MDN] aby uzyskać tablicę nazw właściwości :

Object.keys(data).forEach(function(prop) {
  // `prop` is the property name
  // `data[prop]` is the property value
});

Tablice

Do iteracji wszystkich elementów data.items array , używamy pętli for:

for(let i = 0, l = data.items.length; i < l; i++) {
    // `i` will take on the values `0`, `1`, `2`,..., i.e. in each iteration
    // we can access the next element in the array with `data.items[i]`, example:
    // 
    // var obj = data.items[i];
    // 
    // Since each element is an object (in our example),
    // we can now access the objects properties with `obj.id` and `obj.name`. 
    // We could also use `data.items[i].id`.
}

Można również użyć for...in do iteracji tablic, ale są powody, dla których należy tego unikać: dlaczego jest ' for (var item in list)' z tablice uważane za złe praktyki w JavaScript?.

Przy coraz większym wsparciu przeglądarki ECMAScript 5, metoda array forEach [MDN] staje się również ciekawą alternatywą:

data.items.forEach(function(value, index, array) {
    // The callback is executed for each element in the array.
    // `value` is the element itself (equivalent to `array[index]`)
    // `index` will be the index of the element in the array
    // `array` is a reference to the array itself (i.e. `data.items` in this case)
}); 

W środowiskach obsługujących ES2015 (ES6) można również użyć for...of [MDN] pętli, która działa nie tylko dla tablic, ale dla każdego iterable:

for (const item of data.items) {
   // `item` is the array element, **not** the index
}

W każdym iteracja, for...of bezpośrednio daje nam kolejny element iterable, nie ma "indeksu" do dostępu lub użycia.


Co jeśli "głębokość" struktury danych jest mi nieznana?

Oprócz nieznanych kluczy, "głębia" struktury danych (tj. liczba zagnieżdżonych obiektów) może być również nieznana. Dostęp do głęboko zagnieżdżonych właściwości zazwyczaj zależy od dokładnej struktury danych.

Ale jeśli struktura danych zawiera powtarzające się wzorce, np. reprezentacji drzewa binarnego, rozwiązanie zazwyczaj obejmuje do rekurencyjnie [Wikipedia] dostęp do każdego poziomu struktury danych.

Oto przykład, aby uzyskać pierwszy węzeł liścia drzewa binarnego:]}
function getLeaf(node) {
    if (node.leftChild) {
        return getLeaf(node.leftChild); // <- recursive call
    }
    else if (node.rightChild) {
        return getLeaf(node.rightChild); // <- recursive call
    }
    else { // node must be a leaf node
        return node;
    }
}

const first_leaf = getLeaf(root);

const root = {
    leftChild: {
        leftChild: {
            leftChild: null,
            rightChild: null,
            data: 42
        },
        rightChild: {
            leftChild: null,
            rightChild: null,
            data: 5
        }
    },
    rightChild: {
        leftChild: {
            leftChild: null,
            rightChild: null,
            data: 6
        },
        rightChild: {
            leftChild: null,
            rightChild: null,
            data: 7
        }
    }
};
function getLeaf(node) {
    if (node.leftChild) {
        return getLeaf(node.leftChild);
    } else if (node.rightChild) {
        return getLeaf(node.rightChild);
    } else { // node must be a leaf node
        return node;
    }
}

console.log(getLeaf(root).data);

Bardziej ogólnym sposobem dostępu do zagnieżdżonej struktury danych z nieznanymi kluczami i głębią jest przetestowanie typu wartości i odpowiednie działanie.

Oto przykład, który dodaje wszystkie prymitywne wartości wewnątrz zagnieżdżonej struktury danych w tablicę (zakładając, że nie zawiera ona żadnych funkcji). Jeśli napotkamy obiekt (lub tablicę), po prostu wywołujemy toArray ponownie na tej wartości (wywołanie rekurencyjne).

function toArray(obj) {
    const result = [];
    for (const prop in obj) {
        const value = obj[prop];
        if (typeof value === 'object') {
            result.push(toArray(value)); // <- recursive call
        }
        else {
            result.push(value);
        }
    }
    return result;
}

const data = {
  code: 42,
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 2,
    name: 'bar'
  }]
};


function toArray(obj) {
  const result = [];
  for (const prop in obj) {
    const value = obj[prop];
    if (typeof value === 'object') {
      result.push(toArray(value));
    } else {
      result.push(value);
    }
  }
  return result;
}

console.log(toArray(data));


Pomocnicy

Ponieważ struktura złożonego obiektu lub tablicy nie musi być oczywista, możemy sprawdzić wartość na każdym kroku, aby zdecydować, jak przejść dalej. console.log [MDN] oraz console.dir [MDN] pomóż nam to zrobić. Na przykład (wyjście konsoli Chrome):

> console.log(data.items)
 [ Object, Object ]

Tutaj widzimy, że data.items jest tablicą z dwoma elementami, które są obiema obiektami. W konsoli Chrome obiekty można nawet natychmiast rozszerzyć i sprawdzić.

> console.log(data.items[1])
  Object
     id: 2
     name: "bar"
     __proto__: Object

To mówi nam, że data.items[1] jest obiektem, a po jego rozwinięciu widzimy, że ma trzy właściwości, id, name i __proto__. Ta ostatnia jest wewnętrzną własnością używaną do prototyp łańcucha obiektu. Łańcuch prototypów i dziedziczenie nie są jednak dostępne dla tej odpowiedzi.

 1259
Author: Felix Kling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-16 19:10:23

Możesz uzyskać do niego dostęp w ten sposób

data.items[1].name

Lub

data["items"][1]["name"]

Obie drogi są równe.

 82
Author: vitmalina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-14 03:29:19

Jeśli próbujesz uzyskać dostęp do item z przykładowej struktury przez id lub name, bez znajomości jego pozycji w tablicy, najprostszym sposobem na to jest użycie podkreślenia .biblioteka js:

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

_.find(data.items, function(item) {
  return item.id === 2;
});
// Object {id: 2, name: "bar"}

Z mojego doświadczenia wynika, że używanie funkcji wyższego rzędu zamiast pętli for lub for..in powoduje, że kod jest łatwiejszy do rozumowania, a przez to łatwiejszy do utrzymania.

Tylko moje 2 centy.
 36
Author: holographic-principle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-13 10:25:38

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ą one podobne do wyrażeń funkcyjnych , ale wiążą wartość this leksykalnie.

Object.keys(), Object.values() (ES 2017) oraz Object.entries() (ES 2017)

Object.keys() zwraca tablicę kluczy obiektu, Object.values() zwraca tablicę wartości obiektu, a Object.entries() zwraca tablicę klucze obiektu i odpowiadające im wartości w formacie [key, value].

const obj = {
  a: 1
 ,b: 2
 ,c: 3
}

console.log(Object.keys(obj)) // ['a', 'b', 'c']
console.log(Object.values(obj)) // [1, 2, 3]
console.log(Object.entries(obj)) // [['a', 1], ['b', 2], ['c', 3]]

Object.entries() z pętlą for-of i przypisaniem destrukcji

const obj = {
  a: 1
 ,b: 2
 ,c: 3
}

for (const [key, value] of Object.entries(obj)) {
  console.log(`key: ${key}, value: ${value}`)
}

Bardzo wygodne jest iterację wyniku Object.entries() za pomocąpętli For-of Iprzypisania destrukcji .

Pętla For-of pozwala na iterację elementów tablicy. Składnia to for (const element of array) (możemy zamienić const na var lub let, ale lepiej użyć const, jeśli nie zamierza zmodyfikować element).

Przypisanie destrukcji pozwala wyodrębnić wartości z tablicy lub obiektu i przypisać je do zmiennych. W tym przypadku const [key, value] oznacza, że zamiast przypisać tablicę [key, value] do element, przypisujemy pierwszy element tej tablicy do key, a drugi do value. Jest to równoważne:

for (const element of Object.entries(obj)) {
  const key = element[0]
       ,value = element[1]
}

Jak widzisz, destrukcja sprawia, że jest to o wiele prostsze.

Array.prototype.every() oraz Array.prototype.some()

The every() metoda zwraca true jeśli określona funkcja zwrotna zwraca true dla każdego elementu tablicy. Metoda some() zwraca true jeśli określona funkcja zwrotna zwraca true dla jakiegoś (co najmniej jednego) elementu.

const arr = [1, 2, 3]

// true, because every element is greater than 0
console.log(arr.every(x => x > 0))
// false, because 3^2 is greater than 5
console.log(arr.every(x => Math.pow(x, 2) < 5))
// true, because 2 is even (the remainder from dividing by 2 is 0)
console.log(arr.some(x => x % 2 === 0))
// false, because none of the elements is equal to 5
console.log(arr.some(x => x === 5))

Array.prototype.find() oraz Array.prototype.filter()

Metody find() zwracają pierwszy element spełniający podaną funkcję wywołania zwrotnego. Metoda filter() zwraca tablicę wszystkie elementy, które spełniają podaną funkcję zwrotną.

const arr = [1, 2, 3]

// 2, because 2^2 !== 2
console.log(arr.find(x => x !== Math.pow(x, 2)))
// 1, because it's the first element
console.log(arr.find(x => true))
// undefined, because none of the elements equals 7
console.log(arr.find(x => x === 7))

// [2, 3], because these elements are greater than 1
console.log(arr.filter(x => x > 1))
// [1, 2, 3], because the function returns true for all elements
console.log(arr.filter(x => true))
// [], because none of the elements equals neither 6 nor 7
console.log(arr.filter(x => x === 6 || x === 7))

Array.prototype.map()

Metoda map() zwraca tablicę z wynikami wywołania dostarczonej funkcji wywołania zwrotnego na elementach tablicy.

const arr = [1, 2, 3]

console.log(arr.map(x => x + 1)) // [2, 3, 4]
console.log(arr.map(x => String.fromCharCode(96 + x))) // ['a', 'b', 'c']
console.log(arr.map(x => x)) // [1, 2, 3] (no-op)
console.log(arr.map(x => Math.pow(x, 2))) // [1, 4, 9]
console.log(arr.map(String)) // ['1', '2', '3']

Array.prototype.reduce()

Metoda reduce() redukuje tablicę do pojedynczej wartości przez wywołanie dostarczonej funkcji wywołania zwrotnego z dwoma żywioły.

const arr = [1, 2, 3]

// Sum of array elements.
console.log(arr.reduce((a, b) => a + b)) // 6
// The largest number in the array.
console.log(arr.reduce((a, b) => a > b ? a : b)) // 3

Metoda reduce() pobiera opcjonalny drugi parametr, który jest wartością początkową. Jest to przydatne, gdy tablica, na której wywołujesz reduce() może mieć zero lub jeden element. Na przykład, jeśli chcemy utworzyć funkcję sum(), która pobiera tablicę jako argument i Zwraca sumę wszystkich elementów, możemy napisać ją w następujący sposób:

const sum = arr => arr.reduce((a, b) => a + b, 0)

console.log(sum([]))     // 0
console.log(sum([4]))    // 4
console.log(sum([2, 5])) // 7
 35
Author: Michał Perłakowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-22 18:38:41

Czasami pożądane jest uzyskanie dostępu do zagnieżdżonego obiektu za pomocą łańcucha znaków. Proste podejście jest pierwszym poziomem, na przykład

var obj = { hello: "world" };
var key = "hello";
alert(obj[key]);//world

Ale często tak nie jest w przypadku złożonego json. 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. Rekurencyjne podejście do nawigacji po json jest najlepsze, a sposób wykorzystania tej rekurencji zależy od rodzaju wyszukiwanych danych. Jeśli w grę wchodzą wyrażenia warunkowe, a json search może być dobrym narzędziem do użycia.

Jeżeli dostępna właściwość jest już znana, ale ścieżka jest złożona, na przykład w tym obiekcie

var obj = {
 arr: [
    { id: 1, name: "larry" },    
    { id: 2, name: "curly" },
    { id: 3, name: "moe" }
 ]
};

I wiesz, że chcesz uzyskać pierwszy wynik tablicy w obiekcie, być może chciałbyś użyć

var moe = obj["arr[0].name"];

Spowoduje to jednak wyjątek, ponieważ nie ma właściwości obiektu o tej nazwie. Rozwiązaniem, aby móc tego użyć, byłoby spłaszczenie aspektu drzewa obiektu. Można to zrobić rekurencyjnie.

function flatten(obj){
 var root = {};
 (function tree(obj, index){
   var suffix = toString.call(obj) == "[object Array]" ? "]" : "";
   for(var key in obj){
    if(!obj.hasOwnProperty(key))continue;
    root[index+key+suffix] = obj[key];
    if( toString.call(obj[key]) == "[object Array]" )tree(obj[key],index+key+suffix+"[");
    if( toString.call(obj[key]) == "[object Object]" )tree(obj[key],index+key+suffix+".");   
   }
 })(obj,"");
 return root;
}

Teraz obiekt złożony może zostać spłaszczony

var obj = previous definition;
var flat = flatten(obj);
var moe = flat["arr[0].name"];//moe

Oto jsFiddle Demo tego podejścia.

 26
Author: Travis J,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:54

To pytanie jest dość stare, więc jako współczesna aktualizacja. Wraz z pojawieniem się ES2015 istnieją alternatywy, aby uzyskać dostęp do wymaganych danych. Istnieje teraz funkcja o nazwie destrukcja obiektów do uzyskiwania dostępu do zagnieżdżonych obiektów.

const data = {
  code: 42,
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 2,
    name: 'bar'
  }]
};

const {
  items: [, {
    name: secondName
  }]
} = data;

console.log(secondName);

Powyższy przykład tworzy zmienną o nazwie secondName z klucza name z tablicy o nazwie items, która mówi o pominięciu pierwszego obiektu w tablicy.

Zwłaszcza, że to chyba przesada dla tego przykładu, as simple array acccess jest łatwiejszy do odczytania, ale przydaje się przy rozbijaniu obiektów w ogóle.

To bardzo krótkie wprowadzenie do konkretnego przypadku użycia, destrukcja może być nietypową składnią, do której można się przyzwyczaić na początku. Polecam przeczytanie dokumentacji przypisania destrukcji Mozilli , aby dowiedzieć się więcej.

 14
Author: Alex KeySmith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-25 09:32:21

Możesz użyć lodash _get funkcji:

var object = { 'a': [{ 'b': { 'c': 3 } }] };

_.get(object, 'a[0].b.c');
// => 3
 14
Author: Sergey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-03 04:24:27

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 twardo zakodować w swoim skrypcie w następujący sposób:

data['items'][1]['name']

Te również działają -

data.items[1].name
data['items'][1].name
data.items[1]['name']

Gdy nie znasz dokładnej nazwy przed ręką, lub użytkownik jest Tym, który podaje nazwę dla Ciebie. Następnie wymagane jest dynamiczne przeszukiwanie struktury danych. Niektórzy sugerowali tutaj, że wyszukiwanie można wykonać za pomocą pętli for, ale jest bardzo prosty sposób na przejście ścieżki za pomocą Array.reduce.

const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] }
const path = [ 'items', '1', 'name']
let result = path.reduce((a,v) => a[v], data)

Ścieżka jest sposobem na powiedzenie: najpierw weź obiekt za pomocą klucza items, który jest tablicą. Następnie weź element 1 - st (0 tablic indeksowych). Na koniec weź obiekt z kluczem name w tym elemencie tablicy, który jest łańcuchem bar.

Jeśli masz bardzo długą ścieżkę, możesz nawet użyć String.split, aby to wszystko ułatwić -

'items.1.name'.split('.').reduce((a,v) => a[v], data)

Jest to po prostu zwykły JavaScript, bez użycia jakichkolwiek biblioteki innych firm, takie jak jQuery lub lodash.

 14
Author: Evgeny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-15 10:17:33
var ourStorage = {


"desk":    {
    "drawer": "stapler"
  },
"cabinet": {
    "top drawer": { 
      "folder1": "a file",
      "folder2": "secrets"
    },
    "bottom drawer": "soda"
  }
};
ourStorage.cabinet["top drawer"].folder2; // Outputs -> "secrets"

Lub

//parent.subParent.subsubParent["almost there"]["final property"]

Zasadniczo, używaj kropki pomiędzy każdym potomkiem, który rozwija się pod nim i gdy masz nazwy obiektów wykonane z dwóch łańcuchó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 dodać do tego, dostęp do zagnieżdżonych tablic stanie się tak:

var ourPets = [
  {
    animalType: "cat",
    names: [
      "Meowzer",
      "Fluffy",
      "Kit-Cat"
    ]
  },
  {
    animalType: "dog",
    names: [
      "Spot",
      "Bowser",
      "Frankie"
    ]
  }
];
ourPets[0].names[1]; // Outputs "Fluffy"
ourPets[1].names[0]; // Outputs "Spot"

Źródło: https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-arrays/

Kolejny bardziej przydatny dokument przedstawiający powyższą sytuację: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Basics#Bracket_notation

Dostęp do nieruchomości przez dot walking: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors#Dot_notation

 14
Author: Johnny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-18 15:03:14

To proste wyjaśnienie:

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

/*
1. `data` is object contain `item` object*/
console.log(data);

/*
2. `item` object contain array of two objects as elements*/
console.log(data.items);

/*
3. you need 2nd element of array - the `1` from `[0, 1]`*/
console.log(data.items[1]);

/*
4. and you need value of `name` property of 2nd object-element of array)*/
console.log(data.items[1].name);
 13
Author: timnavigate,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-18 09:50:06

Na wszelki wypadek, ktoś odwiedza to pytanie w 2017 lub później i szuka łatwego do zapamiętania sposobu, oto rozbudowany post na blogu o dostępie do zagnieżdżonych obiektów w JavaScript bez bycia oszukanym przez

nie można odczytać właściwości 'foo' undefined error

1. Wzór dostępu do zagnieżdżonego obiektu Olivera Steele ' a

Najprostszym i najczystszym sposobem jest użycie zagnieżdżonego wzorca dostępu Olivera Steele ' a

const name = ((user || {}).personalInfo || {}).name;

Z tą notacją, nigdy nie wpadniesz na

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 klucz następnego poziomu będzie zawsze dostępny z istniejącego obiektu lub pustego obiektu , ale nigdy z undefined.

2. Dostęp Do Zagnieżdżonych Obiektów Za Pomocą Array Reduce

Aby mieć dostęp do zagnieżdżonych tablic, możesz napisać własną array reduce util.

const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce((obj, key) =>
        (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}

// pass in your object structure as array elements
const name = getNestedObject(user, ['personalInfo', 'name']);

// to access nested array, just pass in array index as an element the path array.
const city = getNestedObject(user, ['personalInfo', 'addresses', 0, 'city']);
// this will return the city from the first address item.

Istnieje również doskonała obsługa typu minimalna biblioteka typy , która robi to wszystko za Ciebie.

 10
Author: Dinesh Pandiyan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-09 04:01:48

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 będzie:

$..items[1].name

Więc:

var secondName = jsonPath.eval(data, "$..items[1].name");
 9
Author: Andrejs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-26 12:43:46

Dostęp do dynamicznie wielopoziomowego obiektu.

var obj = {
  name: "john doe",
  subobj: {
    subsubobj: {
      names: "I am sub sub obj"
    }
  }
};

var level = "subobj.subsubobj.names";
level = level.split(".");

var currentObjState = obj;

for (var i = 0; i < level.length; i++) {
  currentObjState = currentObjState[level[i]];
}

console.log(currentObjState);

Praca: https://jsfiddle.net/andreitodorut/3mws3kjL/

 9
Author: Andrei Todorut,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-08 06:16:55

Wolę JQuery. Jest czystszy i czytelny.

$.each($.parseJSON(data), function (key, value) {
  alert(value.<propertyname>);
});
 8
Author: Rudy Hinojosa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-18 16:04:07

Jeśli szukasz jednego lub więcej obiektów spełniających określone kryteria, masz kilka opcji za pomocą query-js

//will return all elements with an id larger than 1
data.items.where(function(e){return e.id > 1;});
//will return the first element with an id larger than 1
data.items.first(function(e){return e.id > 1;});
//will return the first element with an id larger than 1 
//or the second argument if non are found
data.items.first(function(e){return e.id > 1;},{id:-1,name:""});

Istnieje również single i singleOrDefault działają podobnie jak odpowiednio first i firstOrDefault. Jedyną różnicą jest to, że będą rzucać, jeśli więcej niż jeden mecz zostanie znaleziony.

Dla dalszego wyjaśnienia zapytania-js możesz zacząć od tego post

 6
Author: Rune FS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-18 08:35:05

The Underscore js Way

, która jest biblioteką JavaScript, która dostarcza całą masę użytecznych helperów functional programming bez rozszerzania żadnych wbudowanych obiektów.

Rozwiązanie:

var data = {
  code: 42,
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 2,
    name: 'bar'
  }]
};

var item = _.findWhere(data.items, {
  id: 2
});
if (!_.isUndefined(item)) {
  console.log('NAME =>', item.name);
}

//using find - 

var item = _.find(data.items, function(item) {
  return item.id === 2;
});

if (!_.isUndefined(item)) {
  console.log('NAME =>', item.name);
}
 6
Author: Mohan Dere,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Stare pytanie, ale jak nikt nie wspomniał lodash (tylko podkreślam).

Jeśli już używasz lodash w swoim projekcie, myślę, że elegancki sposób na zrobienie tego w złożonym przykładzie:

Opt 1

_.get(response, ['output', 'fund', 'data', '0', 'children', '0', 'group', 'myValue'], '')

To samo co:

Opt 2

response.output.fund.data[0].children[0].group.myValue

Różnica między pierwszą i drugą opcją jest taka, że w opcie Opt 1 jeśli w ścieżce brakuje jednej z właściwości (niezdefiniowanej), nie otrzymasz błędu, zwróci ci trzecią parametr.

Dla filtra tablicy lodash ma _.find() ale wolałbym użyć zwykłego filter(). Ale nadal uważam, że powyższa metoda _.get() jest bardzo przydatna przy pracy z naprawdę złożonymi danymi. W przeszłości miałem do czynienia z naprawdę złożonymi interfejsami API i było to przydatne!

Mam nadzieję, że będzie to przydatne dla tych, którzy szukają możliwości manipulowania naprawdę złożonymi danymi, co sugeruje tytuł.

 6
Author: Thiago C. S Ventura,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-01 11:46:35

Nie wydaje mi się, aby questerer dotyczył tylko jednego zagnieżdżonego obiektu, dlatego przedstawiam poniższe demo, aby zademonstrować, jak uzyskać dostęp do węzła głęboko zagnieżdżonego obiektu json. Znajdźmy węzeł o id '5'.

var data = {
  code: 42,
  items: [{
    id: 1,
    name: 'aaa',
    items: [{
        id: 3,
        name: 'ccc'
      }, {
        id: 4,
        name: 'ddd'
      }]
    }, {
    id: 2,
    name: 'bbb',
    items: [{
        id: 5,
        name: 'eee'
      }, {
        id: 6,
        name: 'fff'
      }]
    }]
};

var jsonloop = new JSONLoop(data, 'id', 'items');

jsonloop.findNodeById(data, 5, function(err, node) {
  if (err) {
    document.write(err);
  } else {
    document.write(JSON.stringify(node, null, 2));
  }
});
<script src="https://rawgit.com/dabeng/JSON-Loop/master/JSONLoop.js"></script>
 5
Author: dabeng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-22 09:00:32

Możesz użyć składni jsonObject.key, Aby uzyskać dostęp do wartości. Jeśli chcesz uzyskać dostęp do wartości z tablicy, możesz użyć składni jsonObjectArray[index].key.

Oto przykłady kodu, aby uzyskać dostęp do różnych wartości, aby dać ci pomysł.

        var data = {
            code: 42,
            items: [{
                id: 1,
                name: 'foo'
            }, {
                id: 2,
                name: 'bar'
            }]
        };

        // if you want 'bar'
        console.log(data.items[1].name);

        // if you want array of item names
        console.log(data.items.map(x => x.name));

        // get the id of the item where name = 'bar'
        console.log(data.items.filter(x => (x.name == "bar") ? x.id : null)[0].id);
 5
Author: Rahul Vala,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-17 16:19:48

W 2020 roku możesz użyć @babel / plugin-proposal-optional-chaining bardzo łatwo jest uzyskać dostęp do zagnieżdżonych wartości w obiekcie.

 const obj = {
 foo: {
   bar: {
     baz: class {
   },
  },
 },
};

const baz = new obj?.foo?.bar?.baz(); // baz instance

const safe = new obj?.qux?.baz(); // undefined
const safe2 = new obj?.foo.bar.qux?.(); // undefined

Https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining

Https://github.com/tc39/proposal-optional-chaining

 4
Author: Rathore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-08 06:51:29

Podejście dynamiczne

W poniższej funkcji deep(data,key) możesz użyć dowolnego key string-w Twoim przypadku items[1].name (możesz użyć notacji tablicy [i] na dowolnym poziomie) - jeśli klucz jest nieprawidłowy, to undefined jest return.

let deep = (o,k) => k.split('.').reduce((a,c,i) => {
    let m=c.match(/(.*?)\[(\d*)\]/);
    if(m && a!=null && a[m[1]]!=null) return a[m[1]][+m[2]];
    return a==null ? a: a[c];
},o);

// TEST

let key = 'items[1].name' // arbitrary deep-key

let data = {
    code: 42,
    items: [{ id: 11, name: 'foo'}, { id: 22, name: 'bar'},]
};

console.log( key,'=', deep(data,key) );
 4
Author: Kamil Kiełczewski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-01 12:49:14

Funkcja grep JQuery pozwala filtrować przez tablicę:

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

$.grep(data.items, function(item) {
    if (item.id === 2) {
        console.log(item.id); //console id of item
        console.log(item.name); //console name of item
        console.log(item); //console item object
        return item; //returns item object
    }

});
// Object {id: 2, name: "bar"}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-28 11:25:30
// const path = 'info.value[0].item'
// const obj = { info: { value: [ { item: 'it works!' } ], randominfo: 3 }  }
// getValue(path, obj)

export const getValue = ( path , obj) => {
  const newPath = path.replace(/\]/g, "")
  const arrayPath = newPath.split(/[\[\.]+/) || newPath;

  const final = arrayPath.reduce( (obj, k) => obj ?  obj[k] : obj, obj)
  return final;
}
 2
Author: Michael Dimmitt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-12-03 22:50:24

A pythonic, recursive i functional approach to unravel arbitrary JSON trees:

handlers = {
    list:  iterate,
    dict:  delve,
    str:   emit_li,
    float: emit_li,
}

def emit_li(stuff, strong=False):
    emission = '<li><strong>%s</strong></li>' if strong else '<li>%s</li>'
    print(emission % stuff)

def iterate(a_list):
    print('<ul>')
    map(unravel, a_list)
    print('</ul>')

def delve(a_dict):
    print('<ul>')
    for key, value in a_dict.items():
        emit_li(key, strong=True)
        unravel(value)
    print('</ul>')

def unravel(structure):
    h = handlers[type(structure)]
    return h(structure)

unravel(data)

Gdzie data jest listą Pythona (przetwarzaną z ciągu tekstowego JSON):

data = [
    {'data': {'customKey1': 'customValue1',
           'customKey2': {'customSubKey1': {'customSubSubKey1': 'keyvalue'}}},
  'geometry': {'location': {'lat': 37.3860517, 'lng': -122.0838511},
               'viewport': {'northeast': {'lat': 37.4508789,
                                          'lng': -122.0446721},
                            'southwest': {'lat': 37.3567599,
                                          'lng': -122.1178619}}},
  'name': 'Mountain View',
  'scope': 'GOOGLE',
  'types': ['locality', 'political']}
]
 1
Author: pX0r,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-29 07:55:36

Oto odpowiedź za pomocą object-scan.

Podczas uzyskiwania dostępu do pojedynczego wpisu, ta odpowiedź nie przynosi zbyt wielu korzyści w porównaniu z JavaScript vanilla. Jednak interakcja z wieloma polami w tym samym czasie ta odpowiedź może być bardziej wydajna.

Oto jak można oddziaływać z pojedynczym polem

// const objectScan = require('object-scan');

const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] };

const get = (haystack, needle) => objectScan([needle], {
  abort: true,
  rtn: 'value'
})(haystack);

const set = (haystack, needle, value) => objectScan([needle], {
  abort: true,
  rtn: 'bool',
  filterFn: ({ parent, property }) => {
    parent[property] = value;
    return true;
  }
})(haystack);

console.log(get(data, 'items[1].name'));
// => bar

console.log(set(data, 'items[1].name', 'foo2'));
// => true
console.log(data);
// => { code: 42, items: [ { id: 1, name: 'foo' }, { id: 2, name: 'foo2' } ] }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer : jestem autorem object-scan

A oto jak można współdziałać z wiele pól jednocześnie

// const objectScan = require('object-scan');

const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] };

const get = (haystack, ...needles) => objectScan(needles, {
  joined: true,
  rtn: 'entry'
})(haystack);

const set = (haystack, actions) => objectScan(Object.keys(actions), {
  rtn: 'count',
  filterFn: ({ matchedBy, parent, property }) => {
    matchedBy.forEach((m) => {
      parent[property] = actions[m];
    })
    return true;
  }
})(haystack);

console.log(get(data, 'items[0].name', 'items[1].name'));
// => [ [ 'items[1].name', 'bar' ], [ 'items[0].name', 'foo' ] ]

console.log(set(data, {
  'items[0].name': 'foo1',
  'items[1].name': 'foo2'
}));
// => 2
console.log(data);
// => { code: 42, items: [ { id: 1, name: 'foo1' }, { id: 2, name: 'foo2' } ] }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer : jestem autorem object-scan


I oto jak można znaleźć encję w głęboko zagnieżdżonym obiekcie szukającą po id (jak pytano w komentarzu)

// const objectScan = require('object-scan');

const myData = { code: 42, items: [{ id: 1, name: 'aaa', items: [{ id: 3, name: 'ccc' }, { id: 4, name: 'ddd' }] }, { id: 2, name: 'bbb', items: [{ id: 5, name: 'eee' }, { id: 6, name: 'fff' }] }] };

const findItemById = (haystack, id) => objectScan(['**(^items$).id'], {
  abort: true,
  useArraySelector: false,
  rtn: 'parent',
  filterFn: ({ value }) => value === id
})(haystack);

console.log(findItemById(myData, 5));
// => { id: 5, name: 'eee' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer : jestem autorem object-scan

 0
Author: vincent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-20 19:48:35

Mój stringdata pochodzi z pliku PHP, ale i tak wskazuję tutaj w var. Kiedy bezpośrednio wezmę mój json do obj, nic nie pokaże, dlaczego umieściłem mój plik json jako

var obj=JSON.parse(stringdata); tak więc po tym dostaję message obj i pokazuję w polu alertu potem dostaję data która jest tablicą json i przechowuję w jednej zmiennej {[7] } wtedy odczytuję pierwszy obiekt tej tablicy z wartością klucza jak ta ArrObj[0].id

     var stringdata={
        "success": true,
        "message": "working",
        "data": [{
                  "id": 1,
                  "name": "foo"
         }]
      };

                var obj=JSON.parse(stringdata);
                var key = "message";
                alert(obj[key]);
                var keyobj = "data";
                var ArrObj =obj[keyobj];

                alert(ArrObj[0].id);
 -4
Author: Manthan Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-24 15:57:35

Korzystanie z lodash byłoby dobrym rozwiązaniem

Ex:

var object = { 'a': { 'b': { 'c': 3 } } };                                                                                               
_.get(object, 'a.b.c');                                                                                             
// => 3  
 -5
Author: pradeep gowda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-27 12:34:15