Wie kann ich auf verschachtelte Objekte, Arrays oder JSON zugreifen und diese verarbeiten?

875

Ich habe eine verschachtelte Datenstruktur, die Objekte und Arrays enthält. Wie kann ich die Informationen extrahieren, dh auf einen bestimmten oder mehrere Werte (oder Schlüssel) zugreifen?

Zum Beispiel:

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

Wie kann ich auf namedas zweite Element in zugreifen items?

Felix Kling
quelle
22
@Marcel: Es muss gelesen werden als "Ich habe eine in Daten verschachtelte Datenstruktur oder JSON, wie kann ich auf einen bestimmten Wert zugreifen?". Ich kenne den Unterschied, aber viele Leute suchen nicht nach "JSON" anstatt nach "Objekt". Viele Fragen haben tatsächlich die Form "Wie kann ich in diesem JSON auf X zugreifen?". Der einzige Ort, an dem ich JSON in meiner Antwort erwähne, ist, wo ich erkläre, was es ist. Wenn Sie einen Vorschlag haben, wie Sie dies besser kommunizieren können, bin ich ganz Ohr.
Felix Kling
Mögliches Duplikat von JSON in JavaScript finden
Travis J

Antworten:

1159

Vorbereitungen

JavaScript hat nur einen Datentyp, der mehrere Werte enthalten kann: Objekt . Ein Array ist eine spezielle Objektform.

(Einfache) Objekte haben die Form

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

Arrays haben die Form

[value, value, ...]

Sowohl Arrays als auch Objekte legen eine key -> valueStruktur frei. Schlüssel in einem Array müssen numerisch sein, während jede Zeichenfolge als Schlüssel in Objekten verwendet werden kann. Die Schlüssel-Wert-Paare werden auch als "Eigenschaften" bezeichnet. .

Auf Eigenschaften kann entweder mit Punktnotation zugegriffen werden

const value = obj.someProperty;

oder Klammernotation , wenn der Eigenschaftsname kein gültiger JavaScript- Bezeichnername [spec] wäre oder der Name der Wert einer Variablen ist:

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

Aus diesem Grund kann auf Array-Elemente nur in Klammernotation zugegriffen werden:

const value = arr[5]; // arr.5 would be a syntax error

// property name / index as variable
const x = 5;
const value = arr[x];

Warten Sie ... was ist mit JSON?

JSON ist eine Textdarstellung von Daten, genau wie XML, YAML, CSV und andere. Um mit solchen Daten arbeiten zu können, müssen sie zuerst in JavaScript-Datentypen, dh Arrays und Objekte, konvertiert werden (und wie mit diesen Daten gearbeitet wird, wurde gerade erklärt). Wie JSON analysiert wird, wird in der Frage JSON in JavaScript analysieren erläutert . .

Weiterführendes Lesematerial

Der Zugriff auf Arrays und Objekte ist ein grundlegendes JavaScript-Wissen. Daher ist es ratsam, das MDN-JavaScript-Handbuch zu lesen , insbesondere die Abschnitte



Zugriff auf verschachtelte Datenstrukturen

Eine verschachtelte Datenstruktur ist ein Array oder Objekt, das sich auf andere Arrays oder Objekte bezieht, dh ihre Werte sind Arrays oder Objekte. Auf solche Strukturen kann durch aufeinanderfolgendes Anwenden der Punkt- oder Klammernotation zugegriffen werden.

Hier ist ein Beispiel:

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

Nehmen wir an, wir wollen auf die zugreifen name das zweite Element .

So können wir es Schritt für Schritt machen:

Wie wir sehen können, datahandelt es sich um ein Objekt, daher können wir mithilfe der Punktnotation auf seine Eigenschaften zugreifen. Auf die itemsUnterkunft wird wie folgt zugegriffen:

data.items

Der Wert ist ein Array. Um auf sein zweites Element zuzugreifen, müssen wir die Klammernotation verwenden:

data.items[1]

Dieser Wert ist ein Objekt und wir verwenden erneut die Punktnotation, um auf die nameEigenschaft zuzugreifen . So bekommen wir schließlich:

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

Alternativ hätten wir für jede der Eigenschaften die Klammernotation verwenden können, insbesondere wenn der Name Zeichen enthielt, die ihn für die Verwendung der Punktnotation ungültig gemacht hätten:

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

Ich versuche, auf eine Immobilie zuzugreifen, bekomme aber nur undefinedzurück?

Meistens undefinedhat das Objekt / Array beim Abrufen einfach keine Eigenschaft mit diesem Namen.

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

Verwenden Sie console.logoder console.dirund überprüfen Sie die Struktur des Objekts / Arrays. Die Eigenschaft, auf die Sie zugreifen möchten, ist möglicherweise tatsächlich für ein verschachteltes Objekt / Array definiert.

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

Was ist, wenn die Eigenschaftsnamen dynamisch sind und ich sie vorher nicht kenne?

Wenn die Eigenschaftsnamen unbekannt sind oder wir auf alle Eigenschaften eines Objekts / von Elementen eines Arrays zugreifen möchten, können wir die for...in [MDN] -Schleife für Objekte und die for [MDN] -Schleife für Arrays verwenden, um alle Eigenschaften / Elemente zu durchlaufen.

Objekte

Um alle Eigenschaften von zu durchlaufen data, können wir das Objekt folgendermaßen durchlaufen :

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
}

Abhängig davon, woher das Objekt stammt (und was Sie tun möchten), müssen Sie möglicherweise in jeder Iteration testen, ob die Eigenschaft wirklich eine Eigenschaft des Objekts oder eine geerbte Eigenschaft ist. Sie können dies mit Object#hasOwnProperty [MDN] tun .

Alternativ zu for...inwith hasOwnPropertykönnen Sie Object.keys [MDN] verwenden , um ein Array von Eigenschaftsnamen abzurufen :

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

Arrays

Um alle Elemente des data.items Arrays zu durchlaufen , verwenden wir eine forSchleife:

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`.
}

Man könnte auch verwenden for...in, um über Arrays zu iterieren, aber es gibt Gründe, warum dies vermieden werden sollte: Warum ist 'for (var item in list)' bei Arrays, die in JavaScript als schlechte Praxis angesehen werden? .

Mit der zunehmenden Browserunterstützung von ECMAScript 5 wird auch die Array-Methode forEach [MDN] zu einer interessanten Alternative:

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)
}); 

In Umgebungen, die ES2015 (ES6) unterstützen, können Sie auch die [MDN] -Schleife verwenden, die nicht nur für Arrays, sondern für alle iterierbaren Elemente funktioniert :for...of

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

In jeder Iteration for...ofgibt uns direkt das nächste Element der Iterable, es gibt keinen "Index", auf den zugegriffen oder der verwendet werden kann.


Was ist, wenn mir die "Tiefe" der Datenstruktur unbekannt ist?

Zusätzlich zu unbekannten Schlüsseln ist möglicherweise auch die "Tiefe" der Datenstruktur (dh wie viele verschachtelte Objekte) unbekannt. Wie auf tief verschachtelte Eigenschaften zugegriffen wird, hängt normalerweise von der genauen Datenstruktur ab.

Wenn die Datenstruktur jedoch sich wiederholende Muster enthält, z. B. die Darstellung eines Binärbaums, umfasst die Lösung normalerweise den rekursiven Zugriff [Wikipedia] auf jede Ebene der Datenstruktur.

Hier ist ein Beispiel, um den ersten Blattknoten eines Binärbaums zu erhalten:

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);

Eine allgemeinere Möglichkeit, auf eine verschachtelte Datenstruktur mit unbekannten Schlüsseln und unbekannter Tiefe zuzugreifen, besteht darin, den Typ des Werts zu testen und entsprechend zu handeln.

Hier ist ein Beispiel, das alle primitiven Werte innerhalb einer verschachtelten Datenstruktur zu einem Array hinzufügt (vorausgesetzt, es enthält keine Funktionen). Wenn wir auf ein Objekt (oder Array) stoßen, rufen wir toArraydiesen Wert einfach erneut auf (rekursiver Aufruf).

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;
}



Helfer

Da die Struktur eines komplexen Objekts oder Arrays nicht unbedingt offensichtlich ist, können wir den Wert bei jedem Schritt überprüfen, um zu entscheiden, wie Sie sich weiter bewegen möchten. console.log [MDN] und console.dir [MDN] helfen uns dabei. Zum Beispiel (Ausgabe der Chrome-Konsole):

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

Hier sehen wir, dass dies data.itemsein Array mit zwei Elementen ist, die beide Objekte sind. In der Chrome-Konsole können die Objekte sogar sofort erweitert und überprüft werden.

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

Dies sagt uns, dass data.items[1]es sich um ein Objekt handelt, und nachdem wir es erweitert haben, sehen wir, dass es drei Eigenschaften hat id, nameund __proto__. Letzteres ist eine interne Eigenschaft, die für die Prototypkette des Objekts verwendet wird. Die Prototypkette und die Vererbung sind für diese Antwort jedoch nicht zulässig.

Felix Kling
quelle
3
Einige der hier verlinkten Themen fragen wirklich, wie dies in jQuery zu tun ist. Um fair zu sein, vereinfacht dies hier 1 oder 2 Dinge. Ich bin mir nicht sicher, ob ich dies eher zu einem Megapost machen oder diese separat beantworten soll - die hier behandelten Grundlagen darüber, was ein Objekt ist, was ein Array ist, sind normalerweise das, was wirklich gefragt wird ....
Chris Moschini
1
@ felix-kling Eine Sache ... bei verschachtelten Objekten, wie z. B. let object = {a: 1, b: 2, c: { a: 3, b: 4 }};, wird in diesem Fall ein Array zurückgegeben, das ein Array für jedes verschachtelte Objekt enthält. [ 1, 2, [ 3, 4 ] ]Wäre es nicht besser, im rekursiven Aufruf concat anstelle von push zu verwenden? (erfordert, dass das Ergebnis veränderlich ist)
ElFitz
3
Dies ist die ausführlichste Antwort, die ich je auf Stack Overflow gesehen habe - und sie hat meine Frage beantwortet! Vielen Dank!
William Jones
Auf dieser einen Seite habe ich den Unterschied zwischen ARRAY und OBJ
gelernt
76

Sie können auf diese Weise darauf zugreifen

data.items[1].name

oder

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

Beide Wege sind gleich.

Vitmalina
quelle
Ja, aber Sie können keine Daten ["Elemente"] ausführen. 1.name
neaumusic
5
Erstens ist es viel intuitiver, lesbarer und kürzer;) Ich bevorzuge die Verwendung der Klammerneigenschaftssyntax nur, wenn der Eigenschaftsname variabel ist.
DanteTheSmith
35

Wenn Sie versuchen, itemüber die Beispielstruktur auf eine zuzugreifen, idoder nameohne die Position im Array zu kennen, verwenden Sie am einfachsten die Bibliothek underscore.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"}

Nach meiner Erfahrung werden Funktionen höherer Ordnung anstelle von foroder verwendetfor..in Schleifen zu Code, der einfacher zu verstehen und daher besser zu warten ist.

Nur meine 2 Cent.

holographisches Prinzip
quelle
29

Objekte und Arrays verfügen über zahlreiche integrierte Methoden, die Sie bei der Datenverarbeitung unterstützen können.

Hinweis: In vielen der Beispiele , die ich bin mit Pfeil Funktionen . Sie ähneln Funktionsausdrücken , binden den thisWert jedoch lexikalisch.

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

Object.keys()Gibt ein Array von Objektschlüsseln zurück, Object.values()gibt ein Array von Objektwerten zurück und Object.entries()gibt ein Array von Objektschlüsseln und entsprechenden Werten in einem Format zurück [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() mit einer For-of-Schleife und einer Destrukturierungszuweisung

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

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

Es ist sehr praktisch, das Ergebnis Object.entries()mit einer For-of-Schleife und einer Destrukturierungszuweisung zu wiederholen .

Mit der For-of-Schleife können Sie Array-Elemente iterieren. Die Syntax ist for (const element of array)(wir ersetzen können constmit varoder let, aber es ist besser zu nutzen , constwenn wir nicht ändern wollen element).

Mit der Destrukturierungszuweisung können Sie Werte aus einem Array oder Objekt extrahieren und Variablen zuweisen. In diesem Fall const [key, value]bedeutet dies , dass wir anstelle des [key, value]Arrays elementdas erste Element dieses Arrays keyund das zweite Element zuweisen value. Es ist äquivalent dazu:

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

Wie Sie sehen, macht die Destrukturierung dies viel einfacher.

Array.prototype.every() und Array.prototype.some()

Die every()Methode gibt zurück, truewenn die angegebene Rückruffunktion truefür jedes Element des Arrays zurückgegeben wird. Die some()Methode wird zurückgegeben, truewenn die angegebene Rückruffunktion truefür ein (mindestens ein) Element zurückgegeben wird.

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() und Array.prototype.filter()

Die find()Methode gibt das erste Element zurück, das die bereitgestellte Rückruffunktion erfüllt. Die filter()Methode gibt ein Array aller Elemente zurück, das die bereitgestellte Rückruffunktion erfüllt.

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()

Die map()Methode gibt ein Array mit den Ergebnissen des Aufrufs einer bereitgestellten Rückruffunktion für die Array-Elemente zurück.

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()

Die reduce()Methode reduziert ein Array auf einen einzelnen Wert, indem die bereitgestellte Rückruffunktion mit zwei Elementen aufgerufen wird.

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

Die reduce()Methode verwendet einen optionalen zweiten Parameter, der der Anfangswert ist. Dies ist nützlich, wenn das Array, das Sie aufrufen reduce()können, null oder ein Element enthält. Wenn wir beispielsweise eine Funktion erstellen möchten, sum()die ein Array als Argument verwendet und die Summe aller Elemente zurückgibt, können wir sie folgendermaßen schreiben:

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

Michał Perłakowski
quelle
Das ist meine Lieblingsantwort. Sie könnten auch ein Beispiel für die Schleife nur ein expecific verschachtelten Daten, wie hinzufügenObject.keys(data["items"]).forEach(function(key) { console.log(data["items"][key].id); console.log(data["items"][key].name); });
Silversurfer
25

Manchmal kann es wünschenswert sein, mit einer Zeichenfolge auf ein verschachteltes Objekt zuzugreifen. Der einfache Ansatz ist zum Beispiel die erste Ebene

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

Dies ist jedoch bei komplexen JSON häufig nicht der Fall. Wenn json komplexer wird, werden auch die Ansätze zum Finden von Werten innerhalb des json komplexer. Ein rekursiver Ansatz für die Navigation im JSON ist am besten, und wie diese Rekursion genutzt wird, hängt von der Art der Daten ab, nach denen gesucht wird. Wenn es sich um bedingte Anweisungen handelt, wird eine JSON-Suche durchgeführt ein gutes Werkzeug sein.

Wenn die Eigenschaft, auf die zugegriffen wird, bereits bekannt ist, der Pfad jedoch komplex ist, z. B. in diesem Objekt

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

Und Sie wissen, dass Sie das erste Ergebnis des Arrays im Objekt erhalten möchten, das Sie möglicherweise verwenden möchten

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

Dies führt jedoch zu einer Ausnahme, da keine Eigenschaft eines Objekts mit diesem Namen vorhanden ist. Die Lösung, um dies nutzen zu können, wäre, den Baumaspekt des Objekts zu reduzieren. Dies kann rekursiv erfolgen.

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;
}

Jetzt kann das komplexe Objekt abgeflacht werden

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

Hier wird ein jsFiddle DemoAnsatz verwendet.

Travis J.
quelle
WTH möchten Sie obj["arr[0].name"]anstelle von verwenden obj.arr[0].name? Mit Ausnahme der Serialisierung müssen / wollen Sie sich kaum mit abgeflachten Objekten befassen .
Bergi
@Bergi - Ich sehe diese Frage häufig und da diese kanonisch verwendet wird, habe ich eine Antwort auf diese Version veröffentlicht. Wenn es vermeidbar ist, ist es viel schneller, obj.arr [0] .name zu verwenden, aber manchmal möchten Leute String-Accessoren weitergeben, und dies ist ein Beispiel dafür.
Travis J
Urgh. Es gibt jedoch kaum einen Grund, das gesamte Objekt zu reduzieren, nur um einen einzelnen Zeichenfolgenpfad zu verwenden. Sie können dies einfach analysieren und eine dynamische Suche durchführen.
Bergi
14

Diese Frage ist ziemlich alt, also als zeitgemäßes Update. Mit dem Start von ES2015 gibt es Alternativen, um die benötigten Daten zu erhalten. Es gibt jetzt eine Funktion namens Objektzerstörung für den Zugriff auf verschachtelte Objekte.

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

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

console.log(secondName);

Im obigen Beispiel wird eine secondNamevom nameSchlüssel aufgerufene Variable aus einem Array namens " itemsLonely" erstellt, Sprichwort überspringt das erste Objekt im Array.

Insbesondere ist es für dieses Beispiel wahrscheinlich übertrieben, da ein einfacher Array-Zugriff leichter zu lesen ist, aber es ist nützlich, wenn Objekte im Allgemeinen auseinandergebrochen werden.

Dies ist eine sehr kurze Einführung in Ihren speziellen Anwendungsfall. Destrukturierung kann eine ungewöhnliche Syntax sein, an die Sie sich zunächst gewöhnen müssen. Ich würde empfehlen, Mozillas Destructuring Assignment-Dokumentation zu lesen , um mehr zu erfahren.

Alex KeySmith
quelle
13

Um auf ein verschachteltes Attribut zuzugreifen, müssen Sie dessen Namen angeben und dann das Objekt durchsuchen.

Wenn Sie den genauen Pfad bereits kennen, können Sie ihn wie folgt in Ihrem Skript fest codieren:

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

diese funktionieren auch -

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

Wenn Sie den genauen Namen vorher nicht kennen oder ein Benutzer derjenige ist, der den Namen für Sie bereitstellt. Dann ist ein dynamisches Durchsuchen der Datenstruktur erforderlich. Einige schlugen hier vor, dass die Suche mit einer forSchleife durchgeführt werden kann, aber es gibt eine sehr einfache Möglichkeit, einen Pfad mit zu durchlaufen 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)

Der Pfad ist eine Möglichkeit zu sagen: Nehmen Sie zuerst das Objekt mit dem Schlüssel items, der zufällig ein Array ist. Nehmen Sie dann das 1Element -st (0 Index-Arrays). Nehmen Sie zuletzt das Objekt mit dem Schlüssel namein das Array-Element, das zufällig die Zeichenfolge ist bar.

Wenn Sie einen sehr langen Weg haben, können Sie dies sogar nutzen String.split, um all dies zu vereinfachen -

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

Dies ist einfach nur JavaScript, ohne Bibliotheken von Drittanbietern wie jQuery oder lodash zu verwenden.

Evgeny
quelle
13
var ourStorage = {


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

oder

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

Verwenden Sie grundsätzlich einen Punkt zwischen jedem Nachkommen, der sich darunter entfaltet, und wenn Sie Objektnamen aus zwei Zeichenfolgen haben, müssen Sie die Notation ["obj Name"] verwenden. Andernfalls würde nur ein Punkt ausreichen;

Quelle: https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-objects

Um dies hinzuzufügen, würde der Zugriff auf verschachtelte Arrays folgendermaßen erfolgen:

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"

Quelle: https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-arrays/

Ein weiteres nützlicheres Dokument, das die obige Situation darstellt: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Basics#Bracket_notation

Immobilienzugriff über Dot Walking: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors#Dot_notation

Johnny
quelle
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. - Aus dem Rückblick
Robert
1
Ich habe den Beitrag bearbeitet. Trotzdem waren die Leute schnell dabei, einen schlechten Ruf zu geben. Nächstes Mal werde ich keine Antwort geben.
Johnny
1
@Riddick nicht unterlassen, nur sicherstellen, dass Sie nicht nur einen Link
posten
12

Sie könnten folgende lodash _getFunktion verwenden:

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

_.get(object, 'a[0].b.c');
// => 3
Sergey
quelle
9

Die Verwendung von JSONPath ist eine der flexibelsten Lösungen, wenn Sie bereit sind, eine Bibliothek einzuschließen : https://github.com/s3u/JSONPath (Knoten und Browser)

Für Ihren Anwendungsfall wäre der JSON-Pfad:

$..items[1].name

damit:

var secondName = jsonPath.eval(data, "$..items[1].name");
Andrejs
quelle
1
Die Verwendung von eval () ist keine gute Lösung. Stattdessen kann eine erstklassige Funktion verwendet werden.
Pradeep Gowda
8

Für den Fall, dass jemand diese Frage 2017 oder später besucht und nach einem leicht zu merkenden Weg sucht , finden Sie hier einen ausführlichen Blog-Beitrag zum Zugriff auf verschachtelte Objekte in JavaScript, ohne von ihm verwirrt zu werden

Die Eigenschaft 'foo' von undefined kann nicht gelesen werden Fehlers werden

1. Oliver Steeles verschachteltes Objektzugriffsmuster

Am einfachsten und saubersten ist es, das Zugriffsmuster für verschachtelte Objekte von Oliver Steele zu verwenden

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

Mit dieser Notation werden Sie nie begegnen

Die Eigenschaft 'name' von undefined kann nicht gelesen werden .

Grundsätzlich prüfen Sie, ob ein Benutzer vorhanden ist. Wenn nicht, erstellen Sie im laufenden Betrieb ein leeres Objekt. Auf diese Weise wird auf den Schlüssel der nächsten Ebene immer von einem vorhandenen oder leeren Objekt aus zugegriffen , jedoch niemals von undefiniert.

2. Greifen Sie mit Array Reduce auf verschachtelte Objekte zu

Um auf verschachtelte Arrays zugreifen zu können, können Sie Ihr eigenes Array schreiben.

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.

Es gibt auch einen exzellenten Typ, der nur minimale Bibliotheksfehler verarbeitet , der all dies für Sie erledigt.

Dinesh Pandiyan
quelle
3
Diese Frage bezieht sich hauptsächlich auf vorhandene Zugriffseigenschaften. Es gibt bereits eine Frage zu dem, worauf Sie sich beziehen (und die meisten Ihrer Lösungen bereits enthalten): Greifen Sie sicher auf verschachtelte Javascript-Objekte zu oder greifen Sie mit einem Zeichenfolgenschlüssel auf verschachtelte JavaScript-Objekte zu . Aber trotzdem: "Leider können Sie mit diesem Trick nicht auf verschachtelte Arrays zugreifen." Warum nicht? Arrays sind Objekte, daher sollte es genauso gut funktionieren. Können Sie ein Beispiel nennen, wo dies nicht der Fall ist?
Felix Kling
1
@FelixKling Wenn wir versuchen, auf Arrays mit Oliver Steele-Muster zuzugreifen, können wir kein Array mit der Länge 'n' im laufenden Betrieb erstellen und auf den n-ten Index zugreifen, ohne den Fehler 'undefined' zu erhalten. Ex. ((user || {}).address || new Array(3))[1].name
Dinesh Pandiyan
3
Sie wenden Ihr Muster nicht konsequent an. Natürlich ...[1].barwürde dies zu einem Fehler führen, wenn das Element 1nicht vorhanden wäre. Aber das ist auch der Fall, ....foo.barwenn fooes nicht existiert. Sie müssen auch den Zugriff "bewachen" 1, genau wie Sie jeden anderen Zugang zu Eigentum "bewachen". Ein Array ist nur ein Objekt. Ein "Array-Element" ist nur eine Eigenschaft. Richtig angewendet wäre es (((user || {}).address || {})[1] || {}).name.
Felix Kling
1
Das ist toll. Es hat mich nicht so getroffen. Vielen Dank an @FelixKling, ich werde die Blog-Beiträge aktualisieren.
Dinesh Pandiyan
2
@ DineshPandiyan Sie sollten offenlegen, dass Sie der Autor von typy sind, ich bin gerade hierher gekommen, nachdem ich Ihren Blog-Beitrag
gelesen habe
8

Ich bevorzuge JQuery. Es ist sauberer und leicht zu lesen.

$.each($.parseJSON(data), function (key, value) {
  alert(value.<propertyname>);
});
Rudy Hinojosa
quelle
7

Zugriff auf dynamisch mehrstufige Objekte.

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);

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

Andrei Todorut
quelle
6

Wenn Sie nach einem oder mehreren Objekten suchen, die bestimmte Kriterien erfüllen, haben Sie mit query-js einige Optionen

//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:""});

Es gibt auch ein singleund ein singleOrDefault, wie sie funktionierenfirst und firstOrDefaultjeweils. Der einzige Unterschied ist, dass sie werfen, wenn mehr als eine Übereinstimmung gefunden wird.

Zur weiteren Erläuterung von query-js können Sie mit diesem Beitrag beginnen

Rune FS
quelle
Ich würde gerne wissen, wie dies verbessert werden könnte. Möchtest du einen Kommentar hinterlassen?
Rune FS
6

Der Unterstrich js Weg

Dies ist eine JavaScript-Bibliothek, die eine ganze Reihe nützlicher functional programmingHelfer bereitstellt, ohne integrierte Objekte zu erweitern.

Lösung:

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);
}
Mohan Dere
quelle
6

Alte Frage, aber wie niemand erwähnte lodash (nur unterstreichen).

Falls Sie in Ihrem Projekt bereits lodash verwenden, halte ich dies in einem komplexen Beispiel für eine elegante Möglichkeit:

Opt 1

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

gleich wie:

Opt 2

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

Der Unterschied zwischen der ersten und der zweiten Option besteht in der Option 1 wenn eine der Eigenschaften im Pfad fehlt (undefiniert), kein Fehler angezeigt wird, der dritte Parameter zurückgegeben wird.

Für Array Filter hat lodash _.find()aber ich würde lieber das reguläre verwenden filter(). Aber ich denke immer noch, dass die obige Methode sehr _.get()nützlich ist, wenn Sie mit wirklich komplexen Daten arbeiten. Ich war in der Vergangenheit mit sehr komplexen APIs konfrontiert und es war praktisch!

Ich hoffe, es kann nützlich sein, wer nach Optionen sucht, um wirklich komplexe Daten zu manipulieren, die der Titel impliziert.

Thiago C. S. Ventura
quelle
5

Ich glaube nicht, dass der Fragesteller nur ein verschachteltes Objekt einer Ebene betrifft. Daher präsentiere ich die folgende Demo, um zu demonstrieren, wie auf den Knoten eines tief verschachtelten JSON-Objekts zugegriffen werden kann. Also gut, lasst uns den Knoten mit der ID '5' finden.

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>

dabeng
quelle
Wie greife ich mithilfe von Variablen auf verschachtelte JSON-Objekte zu? data = {a: {b: 'ss'}}; var key = ab data [key] funktioniert nicht
Pasupathi Rajamanickam
3

Sie können die Syntax verwenden, jsonObject.keyum auf den Wert zuzugreifen. Wenn Sie von einem Array aus auf einen Wert zugreifen möchten, können Sie die Syntax verwenden jsonObjectArray[index].key.

Hier sind die Codebeispiele für den Zugriff auf verschiedene Werte, um Ihnen die Idee zu geben.

        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);

Rahul Vala
quelle
3

Dynamischer Ansatz

In der folgenden deep(data,key)Funktion können Sie eine beliebige keyZeichenfolge verwenden - in Ihrem Fall items[1].name(Sie können die Array-Notation [i]auf jeder Ebene verwenden) - wenn der Schlüssel ungültig ist, wird undefined zurückgegeben.

Kamil Kiełczewski
quelle
2

Ein pythonischer, rekursiver und funktionaler Ansatz zum Entschlüsseln beliebiger JSON-Bäume:

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)

Dabei handelt es sich bei den Daten um eine Python-Liste (analysiert aus einer JSON-Textzeichenfolge):

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']}
]
pX0r
quelle
6
Diese Frage bezieht sich auf JavaScript, nicht auf Python. Ich bin mir nicht sicher, ob es eine entsprechende Frage für Python gibt.
Felix Kling
2

Mit der grep- Funktion von jQuery können Sie durch ein Array filtern:

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>


quelle
2
// 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;
}
Michael Dimmitt
quelle
-4

Meine stringdatakommt aus der PHP-Datei, aber trotzdem gebe ich hier in an var. Wenn ich meinen objJSON direkt einnehme , wird nichts angezeigt, weshalb ich meine JSON-Datei als

var obj=JSON.parse(stringdata); so nach , dass ich bekommen messageobj und in Alert - Box zeigen , dann bekomme ich datadas ist Json - Array und Speicher in einem varible ArrObjdann las ich das erste Objekt dieser Array mit Schlüssel-Wert wie folgtArrObj[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);
Manthan Patel
quelle
2
Das Beispiel ist verwirrend, da stringjsones sich nicht um eine Zeichenfolge handelt.
Felix Kling