Comment puis-je accéder et traiter des objets imbriqués, des tableaux ou JSON ?

J'ai une structure de données imbriquée contenant des objets et des tableaux. Comment puis-je extraire l'information, c'est-à-dire accéder à une ou plusieurs valeurs (ou clés) ?

Par example:

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

Comment puis-je accéder nameau deuxième élément dansitems ?


Solution du problème

Préliminaires

JavaScript n'a qu'un seul type de données qui peut contenir plusieurs valeurs: Object. Un tableau est une forme spéciale d'objet.

Les objets (simples) ont la forme

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

Les tableaux ont la forme

[value, value,...]

Les tableaux et les objets exposent une key -> valuestructure. Les clés d'un tableau doivent être numériques, alors que n'importe quelle chaîne peut être utilisée comme clé dans les objets. Les paires clé-valeur sont également appelées les "propriétés".

Les propriétés sont accessibles soit en utilisant la notation par points

const value = obj.someProperty;

ou notation entre parenthèses, si le nom de la propriété n'est pas un nom d'identifiant JavaScript valide [spec], ou si le nom est la valeur d'une variable:

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

Pour cette raison, les éléments de tableau ne sont accessibles qu'en utilisant la notation entre parenthèses :

const value = arr[5]; // arr.5 would be a syntax error
// property name / index as variable
const x = 5;
const value = arr[x];

Attendez... qu'en est-il de JSON ?

JSON est une représentation textuelle de données, tout comme XML, YAML, CSV et autres. Pour travailler avec de telles données, elles doivent d'abord être converties en types de données JavaScript, c'est-à-dire des tableaux et des objets (et comment travailler avec ceux-ci vient d'être expliqué). Comment analyser JSON est expliqué dans la question Parse JSON in JavaScript?.

Matériel de lecture supplémentaire

Comment accéder aux tableaux et aux objets est une connaissance fondamentale de JavaScript et il est donc conseillé de lire le Guide JavaScript MDN, en particulier les sections


  • Travailler avec des objets

  • Tableaux

  • JavaScript éloquent - Structures de données


Accéder aux structures de données imbriquées

Une structure de données imbriquée est un tableau ou un objet qui fait référence à d'autres tableaux ou objets, c'est-à-dire que ses valeurs sont des tableaux ou des objets. Ces structures sont accessibles en appliquant consécutivement une notation par points ou parenthèses.

Voici un exemple:

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

Supposons que nous voulions accéder au namedeuxième élément.

Voici comment nous pouvons le faire étape par étape:

Comme nous pouvons le voir data, c'est un objet, nous pouvons donc accéder à ses propriétés en utilisant la notation par points. La itemspropriété est accessible comme suit:

data.items

La valeur est un tableau, pour accéder à son deuxième élément, nous devons utiliser la notation parenthèse :

data.items[1]

Cette valeur est un objet et nous utilisons à nouveau la notation par points pour accéder à la namepropriété. On obtient donc finalement:

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

Alternativement, nous aurions pu utiliser la notation entre parenthèses pour l'une des propriétés, en particulier si le nom contenait des caractères qui l'auraient rendu invalide pour l'utilisation de la notation par points :

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

J'essaie d'accéder à une propriété mais je n'obtiens qu'un undefinedretour?

La plupart du temps, lorsque vous obtenez undefined, l'objet/tableau n'a tout simplement pas de propriété portant ce nom.

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

Utilisez console.logou console.diret inspectez la structure de l'objet/tableau. La propriété à laquelle vous essayez d'accéder peut être en fait définie sur un objet/tableau imbriqué.

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

Que se passe-t-il si les noms de propriété sont dynamiques et que je ne les connais pas à l'avance ?

Si les noms de propriété sont inconnus ou si nous voulons accéder à toutes les propriétés d'un objet/éléments d'un tableau, nous pouvons utiliser la boucle for...in [MDN] pour les objets et la boucle for [MDN] pour les tableaux pour itérer sur toutes les propriétés/éléments.

Objets

Pour itérer sur toutes les propriétés de data, nous pouvons itérer sur l' objet comme suit :

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
}

Selon l'origine de l'objet (et ce que vous voulez faire), vous devrez peut-être tester à chaque itération si la propriété est réellement une propriété de l'objet ou s'il s'agit d'une propriété héritée. Vous pouvez le faire avec Object#hasOwnProperty [MDN].

Comme alternative à for...inwith hasOwnProperty, vous pouvez utiliser Object.keys [MDN] pour obtenir un tableau de noms de propriétés:

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

Tableaux

Pour itérer sur tous les éléments du data.items tableau, nous utilisons une forboucle :

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

On pourrait également utiliser for...inpour itérer sur des tableaux, mais il y a des raisons pour lesquelles cela devrait être évité: Pourquoi 'for(var item in list)' avec des tableaux est-il considéré comme une mauvaise pratique en JavaScript?.

Avec la prise en charge croissante d'ECMAScript 5 par les navigateurs, la méthode de tableau forEach [MDN] devient également une alternative intéressante :

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

Dans les environnements prenant en charge ES2015 (ES6), vous pouvez également utiliser la boucle [MDN], qui fonctionne non seulement pour les tableaux, mais pour tout itérable :for...of

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

A chaque itération, for...ofnous donne directement l'élément suivant de l'itérable, il n'y a pas d'"index" auquel accéder ou utiliser.

Que faire si la "profondeur" de la structure de données m'est inconnue ?

En plus des clés inconnues, la "profondeur" de la structure de données (c'est-à-dire le nombre d'objets imbriqués) dont elle dispose peut également être inconnue. La façon d'accéder aux propriétés profondément imbriquées dépend généralement de la structure exacte des données.

Mais si la structure de données contient des motifs répétitifs, par exemple la représentation d'un arbre binaire, la solution consiste généralement à accéder de manière récursive [Wikipédia] à chaque niveau de la structure de données.

Voici un exemple pour obtenir le premier nœud feuille d'un arbre binaire :

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

Commentaires

Posts les plus consultés de ce blog

Erreur Symfony : "Une exception a été levée lors du rendu d'un modèle"

Détecter les appuis sur les touches fléchées en JavaScript

Une chaîne vide donne "Des erreurs ont été détectées dans les arguments de la ligne de commande, veuillez vous assurer que tous les arguments sont correctement définis"