Parcourir et manipuler des objets efficacement avec JavaScript
Les objets JavaScript sont omniprésents. Ils structurent nos données, encapsulent des informations, et sont souvent au cœur de nos interactions avec les API ou des bases de données. Pourtant, dès qu’il s’agit de les manipuler, certains réflexes peuvent nous jouer des tours.
Aujourd’hui, nous allons explorer comment transformer un objet complexe en un fragment HTML dynamique, mais pas n’importe lequel : une liste descriptive, parfaite pour afficher des informations détaillées. Imaginons que nous sommes en train de concevoir une page dédiée aux groupes musicaux emblématiques. Chaque genre musical sera une entrée, et chaque groupe sera accompagné de son nom, d’un lien Wikipédia et d’une brève description. Un parfait mélange d’information et de pratique.
L’objet enrichi : des données riches, une structure adaptée
Voici les données que nous allons manipuler. Ce n’est plus un simple tableau de chaînes de caractères, mais un tableau d’objets contenant plusieurs propriétés :
const genres = {
"Rocks des années 72": [
{
name: "Led Zeppelin",
wikipedia: "https://fr.wikipedia.org/wiki/Led_Zeppelin",
description: "Un des groupes les plus influents du hard rock."
},
{
name: "Deep Purple",
wikipedia: "https://fr.wikipedia.org/wiki/Deep_Purple",
description: "Connu pour l’iconique Smoke on the Water."
},
{
name: "Black Sabbath",
wikipedia: "https://fr.wikipedia.org/wiki/Black_Sabbath",
description: "Pionniers du heavy metal."
}
],
"KrautRock": [
{
name: "Can",
wikipedia: "https://fr.wikipedia.org/wiki/Can_(groupe)",
description: "Groupe expérimental influent."
},
{
name: "Neu!",
wikipedia: "https://fr.wikipedia.org/wiki/Neu!",
description: "Précurseur du style motorik."
},
{
name: "Faust",
wikipedia: "https://fr.wikipedia.org/wiki/Faust_(groupe)",
description: "Groupe avant-gardiste emblématique."
}
],
"Post Rock": [
{
name: "Explosions in the Sky",
wikipedia: "https://fr.wikipedia.org/wiki/Explosions_in_the_Sky",
description: "Célèbre pour ses compositions instrumentales."
},
{
name: "Godspeed You! Black Emperor",
wikipedia: "https://fr.wikipedia.org/wiki/Godspeed_You!_Black_Emperor",
description: "Un collectif culte du post-rock."
},
{
name: "Mogwai",
wikipedia: "https://fr.wikipedia.org/wiki/Mogwai_(groupe)",
description: "Un des piliers du post-rock moderne."
}
]
};
Cet objet est structuré pour refléter une réalité plus proche de ce que nous rencontrons dans des projets : des données hiérarchiques avec des propriétés variées.
Premier réflexe : Une boucle for
classique
Quand nous découvrons ce genre de structure, notre premier réflexe est souvent de nous tourner vers une boucle classique. Cela peut fonctionner, mais voyons à quoi cela ressemble dans notre contexte :
for (const genre in genres) {
console.log(`Genre : ${genre}`);
const bands = genres[genre];
for (let i = 0; i < bands.length; i++) {
console.log(` - ${bands[i].name}`);
}
}
Cela semble correct, mais si nous inspectons notre console, plusieurs limitations deviennent évidentes. Par exemple, nous devons vérifier manuellement que les clés parcourues appartiennent bien à notre objet :
if (genres.hasOwnProperty(genre)) {
// Traitement
}
Sans cette vérification, une clé ajoutée par le prototype de l’objet pourrait s’introduire et perturber notre traitement. Cela alourdit notre code et nous éloigne de sa lisibilité.
Approche moderne : Passer à Object.entries
Plutôt que de jongler avec des vérifications et des boucles imbriquées, Object.entries
nous offre une alternative moderne et élégante. Avec elle, nous pouvons parcourir à la fois les clés et les valeurs de notre objet tout en réduisant les risques d’erreurs. Voici comment nous pouvons l’utiliser pour créer notre liste descriptive.
Pour commencer, nous créons un élément <dl>
à l’aide de document.createElement
. Cet élément sera le conteneur principal de notre liste descriptive. C’est ici que nous allons insérer dynamiquement nos termes (<dt>
) et leurs définitions (<dd>
).
const dl = document.createElement('dl');
Ensuite, nous avons besoin de parcourir l’objet genres
, qui contient des genres musicaux et des informations sur les groupes associés. C’est là qu’intervient Object.entries
. Cette méthode est très pratique lorsqu’on travaille avec des objets. Mais que fait-elle exactement ?
Lorsqu’on appelle Object.entries(genres)
, on transforme l’objet en un tableau d’entrées. Chaque entrée est un petit tableau qui contient deux éléments : la clé (par exemple, « Rocks des années 72 ») et la valeur associée (le tableau de groupes). Cela donne quelque chose comme ceci :
[
["Rocks des années 72", [
{ name: "Led Zeppelin", wikipedia: "...", description: "..." },
{ name: "Deep Purple", wikipedia: "...", description: "..." }
]],
["KrautRock", [
{ name: "Can", wikipedia: "...", description: "..." },
{ name: "Neu!", wikipedia: "...", description: "..." }
]]
]
Le gros avantage ici est que nous avons accès simultanément à la clé et à la valeur, ce qui rend le parcours très intuitif. Vous pouvez consulter la documentation officielle de Object.entries
sur MDN pour plus de détails.
Utilisons maintenant Object.entries
pour parcourir cet objet. Nous utilisons une boucle forEach
pour traiter chaque paire [clé, valeur]
. Ici, la clé est le genre musical, et la valeur est le tableau des groupes associés.
Object.entries(genres).forEach(([genre, bands]) => {
const dt = document.createElement('dt');
dt.textContent = genre;
dl.appendChild(dt);
// Autre boucle pour les groupes
});
Dans cette boucle, pour chaque genre, nous créons un élément <dt>
qui contiendra le nom du genre. Cet élément est ensuite ajouté à notre liste descriptive <dl>
grâce à dl.appendChild(dt)
.
Une fois le genre ajouté, nous devons traiter les groupes. Pour cela, nous utilisons une deuxième boucle forEach
qui parcourt le tableau des groupes. Chaque groupe est représenté par un objet contenant plusieurs propriétés, comme name
, wikipedia
et description
.
bands.forEach(({ name, wikipedia, description }) => {
const dd = document.createElement('dd');
dd.innerHTML = `<a href="${wikipedia}" target="_blank">${name}</a> - ${description}`;
dl.appendChild(dd);
});
Pour chaque groupe, nous créons un élément <dd>
où nous insérons un lien hypertexte (vers Wikipédia) et une brève description du groupe. Remarquez que nous utilisons ici innerHTML
pour insérer le contenu HTML directement dans l’élément. Cela nous permet de combiner du texte et des balises comme <a>
dans une seule opération.
Enfin, tout le contenu est ajouté au conteneur <dl>
que nous avons créé au début. Une fois la boucle terminée, nous ajoutons cet élément au DOM, ce qui affiche la liste descriptive sur notre page.
document.body.appendChild(dl);
Cette approche permet de transformer un objet complexe en une structure HTML organisée et interactive. Grâce à Object.entries
, nous simplifions grandement le parcours de l’objet tout en rendant notre code plus lisible et expressif.
Pour voir le résultat final en action, vous pouvez visiter cette démonstration en ligne ici : Liste descriptive des groupes musicaux
Pourquoi Object.entries
facilite-t-il notre vie ?
Avec Object.entries
, nous obtenons un tableau de paires [clé, valeur]
, ce qui nous permet de parcourir les données sans avoir à nous soucier des propriétés héritées. Cela réduit le risque d’erreurs tout en rendant notre code plus expressif. Contrairement à une boucle classique, nous accédons directement à ce dont nous avons besoin, sans avoir à appeler plusieurs fois des méthodes comme hasOwnProperty
.
Techniques avancées : Gagner en flexibilité avec les templates HTML
Si nous souhaitons aller plus loin dans l’optimisation et la réutilisation de nos composants, une approche intéressante consiste à utiliser les balises <template>
disponibles en HTML5. Ces balises permettent de définir des blocs de contenu HTML réutilisables qui ne sont pas immédiatement rendus dans le DOM.
Nous pourrions, par exemple, définir un template pour représenter chaque groupe musical. Le contenu du template pourrait inclure toutes les balises nécessaires, comme le lien vers Wikipédia et la description. Voici comment cela pourrait fonctionner :
<template id="group-template">
<dd>
<a href="" target="_blank"></a>
<span> - </span>
</dd>
</template>
Dans ce code, nous avons un template
avec un <dd>
et des sous-éléments prêts à recevoir des données dynamiques. Ensuite, côté JavaScript, nous pouvons cloner ce contenu pour chaque groupe, tout en remplaçant les valeurs dynamiques comme le nom et le lien.
const template = document.getElementById('group-template');
bands.forEach(({ name, wikipedia, description }) => {
const clone = template.content.cloneNode(true);
const link = clone.querySelector('a');
link.href = wikipedia;
link.textContent = name;
const span = clone.querySelector('span');
span.textContent += description;
dl.appendChild(clone);
});
Cette approche offre plusieurs avantages. Elle sépare clairement la structure HTML du script JavaScript, ce qui améliore la lisibilité et facilite les modifications ultérieures. De plus, en utilisant des templates, nous pouvons également inclure des styles ou des éléments plus complexes sans dupliquer le code.
Vous trouverez des informations complémentaires sur cette technique dans la documentation MDN : Utilisation des templates HTML. Pour voir cette version en action, vous pouvez consulter la démonstration directement en ligne à l’adresse suivante : Liste descriptive des groupes musicaux (avec templates).
Aller plus loin avec Object.entries
Quand on commence à manipuler des objets avec JavaScript, les méthodes modernes comme Object.entries
nous permettent d’explorer des possibilités bien au-delà du simple parcours clé-valeur. Ce n’est pas seulement un outil pour afficher des données : c’est une porte d’entrée vers des manipulations complexes, comme filtrer des informations, transformer des structures ou fusionner des données complémentaires.
Aujourd’hui, explorons deux utilisations avancées de Object.entries
: comment filtrer des données dynamiquement et comment enrichir un objet en fusionnant des sources d’information. Ces techniques sont des atouts précieux dans des projets où les données sont au cœur de l’application.
Première adaptation : Filtrer les données dynamiquement
Imaginons que nous travaillons avec notre objet genres
, mais que nous souhaitons afficher uniquement les groupes dont la description contient un mot-clé spécifique, comme « influents ». Cela nous permettrait de réduire l’affichage à ce qui est vraiment pertinent dans un certain contexte.
Avec Object.entries
, nous pouvons facilement parcourir les genres et filtrer les groupes qui répondent à ce critère. Voici le code :
Dans ce code, nous utilisons plusieurs outils de JavaScript pour manipuler et transformer notre objet genres
. Voici comment cela fonctionne pas à pas.
D’abord, Object.entries(genres)
nous permet de parcourir l’objet en transformant ses paires clé-valeur en un tableau. Chaque entrée de ce tableau est une paire sous la forme [clé, valeur]
, où la clé est le nom du genre musical (par exemple, "Rocks des années 72"
) et la valeur est un tableau contenant les groupes associés. Grâce à cela, nous pouvons manipuler facilement les données avec des méthodes comme forEach
, filter
, ou reduce
.
Ensuite, nous combinons cette structure avec la méthode reduce
. Si vous ne les avez jamais utilisées, imaginez reduce
comme un outil qui « réduit » un ensemble de données à un seul résultat en appliquant une logique spécifique. Ici, nous utilisons reduce
pour construire un nouvel objet appelé filteredGenres
. Ce nouvel objet contiendra uniquement les genres qui ont des groupes répondant à un critère précis, à savoir : une description contenant le mot « influents ».
const filteredGenres = Object.entries(genres).reduce((acc, [genre, bands]) => {
const filteredBands = bands.filter(band => band.description.includes('influents'));
if (filteredBands.length > 0) {
acc[genre] = filteredBands;
}
return acc;
}, {});
Analysons chaque partie :
Object.entries(genres)
Cela transforme notre objet genres
en un tableau d’entrées. Par exemple, la première entrée ressemblerait à ceci :
["Rocks des années 72", [
{ name: "Led Zeppelin", ... },
{ name: "Deep Purple", ... }
]]
Grâce à ce tableau, nous avons accès simultanément au nom du genre (genre
) et à son tableau de groupes (bands
).
La méthode reduce
Cette méthode prend deux choses :
- Un accumulateur (
acc
), qui commence comme un objet vide ({}
) et se remplit progressivement. - Chaque entrée
[genre, bands]
, qui représente le genre musical et son tableau de groupes.
À chaque itération, nous appliquons une logique pour décider si nous ajoutons ce genre à notre accumulateur.
Filtrer les groupes avec filter
Pour chaque genre, nous utilisons bands.filter(...)
pour sélectionner uniquement les groupes qui contiennent le mot « influents » dans leur description. Par exemple, si un genre contient trois groupes et qu’un seul répond au critère, filter
renverra un tableau avec ce seul groupe.
Si le tableau filteredBands
n’est pas vide (c’est-à-dire qu’il contient au moins un groupe), nous ajoutons ce genre à notre nouvel objet filteredGenres
. Sinon, nous l’ignorons.
Le résultat final
Une fois que reduce
a terminé, nous obtenons un objet filteredGenres
qui ne contient que les genres pertinents. Par exemple, si seuls les genres "Rocks des années 72"
et "KrautRock"
contiennent des groupes avec « influents » dans leur description, l’objet ressemblera à ceci :
{
"Rocks des années 72": [
{ name: "Led Zeppelin", ... }
],
"KrautRock": [
{ name: "Can", ... }
]
}
Ce nouvel objet est maintenant beaucoup plus léger et précis. Il est prêt à être utilisé pour générer du HTML, comme nous l’avons fait dans notre exemple précédent, ou pour d’autres traitements spécifiques.
En résumé, Object.entries
nous permet de parcourir l’objet d’origine avec flexibilité, tandis que reduce
et filter
nous aident à extraire et à organiser les données dont nous avons besoin. Si ces concepts sont nouveaux pour vous, n’hésitez pas à expérimenter avec de petits exemples : cela vous aidera à bien comprendre comment ces outils fonctionnent ensemble.
Deuxième adaptation : Fusionner des données complémentaires
Dans cet exemple, nous utilisons Object.entries
pour enrichir les données des groupes musicaux en leur ajoutant une nouvelle propriété : leur année de formation. Cette information est extraite d’un autre objet, groupYears
, qui associe chaque groupe à une année précise.
const groupYears = {
"Led Zeppelin": 1968,
"Deep Purple": 1968,
"Black Sabbath": 1968,
"Can": 1968,
"Neu!": 1971,
"Faust": 1971,
"Explosions in the Sky": 1999,
"Godspeed You! Black Emperor": 1994,
"Mogwai": 1995
};
Si l’année n’est pas disponible pour un groupe, nous attribuons une valeur par défaut : "Année inconnue"
. Regardons de plus près comment cela fonctionne.
const enrichedGenres = Object.entries(genres).reduce((acc, [genre, bands]) => {
acc[genre] = bands.map(band => ({
...band,
year: groupYears[band.name] || "Année inconnue"
}));
return acc;
}, {});
Transformer l’objet genres
en tableau avec Object.entries
Encore une fois, Object.entries(genres)
est utilisé pour convertir l’objet genres
en un tableau d’entrées. Chaque entrée est une paire [clé, valeur]
:
- La clé est le nom du genre musical (par exemple,
"Rocks des années 72"
). - La valeur est un tableau de groupes (comme Led Zeppelin, Deep Purple, etc.).
Cela nous permet de parcourir facilement l’objet tout en ayant simultanément accès à chaque genre et aux groupes qui lui sont associés.
Utiliser reduce
pour construire un nouvel objet enrichi
La méthode reduce
est ici utilisée pour construire un nouvel objet, que nous avons appelé enrichedGenres
. Cet objet est initialement vide ({}
), et à chaque itération, nous y ajoutons un genre enrichi.
À chaque itération, nous traitons un genre à la fois :
- Le genre (
genre
) est ajouté en tant que clé dans l’objetacc
. - Les groupes associés (
bands
) sont transformés grâce àmap
.
Enrichir les données des groupes avec map
map
est une méthode puissante qui permet de transformer chaque élément d’un tableau. Ici, nous utilisons map
pour parcourir la liste des groupes d’un genre et leur ajouter une nouvelle propriété : year
.
Regardons une transformation typique :
bands.map(band => ({
...band,
year: groupYears[band.name] || "Année inconnue"
}))
...band
: Cela copie toutes les propriétés existantes de l’objet band
(comme name
, wikipedia
, et description
) dans un nouvel objet. C’est ce qu’on appelle l’opérateur de décomposition (ou « spread operator »).year
: Nous ajoutons une nouvelle propriété year
. Pour cela, nous recherchons l’année de formation du groupe dans l’objet groupYears
:
Si l’année n’est pas trouvée (par exemple, pour un groupe absent de groupYears
), la valeur par défaut "Année inconnue"
est attribuée.
Si l’année est trouvée (par exemple, "Led Zeppelin"
est associé à 1968
), elle est utilisée.
Le résultat final : Un objet enrichi
Une fois le traitement terminé, enrichedGenres
contient la même structure que genres
, mais chaque groupe est enrichi d’une nouvelle propriété year
. Voici à quoi ressemble cet objet :
{
"Rocks des années 72": [
{
name: "Led Zeppelin",
wikipedia: "https://fr.wikipedia.org/wiki/Led_Zeppelin",
description: "Un des groupes les plus influents du hard rock.",
year: 1968
},
{
name: "Deep Purple",
wikipedia: "https://fr.wikipedia.org/wiki/Deep_Purple",
description: "Connu pour l’iconique Smoke on the Water.",
year: 1968
}
],
"KrautRock": [
{
name: "Can",
wikipedia: "https://fr.wikipedia.org/wiki/Can_(groupe)",
description: "Groupe expérimental influent.",
year: 1968
},
{
name: "Neu!",
wikipedia: "https://fr.wikipedia.org/wiki/Neu!",
description: "Précurseur du style motorik.",
year: 1971
}
]
}
Chaque groupe contient désormais une propriété year
, ce qui peut être utile pour afficher ou trier les données dans une interface.
Pourquoi Object.entries
et map
sont-ils essentiels ici ?
Object.entries
: Permet de parcourir facilement un objet complexe tout en ayant accès à la fois aux clés (genres) et aux valeurs (listes de groupes).map
: Transforme chaque élément d’un tableau (ici, chaque groupe) en ajoutant ou modifiant des propriétés.
Ces deux outils, combinés avec reduce
, rendent ce processus d’enrichissement simple, fluide et lisible.
Et maintenant ?
Ce nouvel objet enrichi peut être utilisé pour des traitements supplémentaires ou pour générer du contenu HTML enrichi. Par exemple, nous pourrions afficher les années de formation des groupes directement dans notre interface utilisateur, offrant ainsi plus d’informations aux visiteurs.
Si ces outils sont nouveaux pour vous, essayez-les avec des exemples simples pour en comprendre les principes : vous serez surpris de leur puissance et de leur flexibilité !
Au-delà du simple parcours
Pour découvrir ces techniques en action, vous pouvez consulter ce fichier en ligne : Techniques avancées avec Object.entries.
Avec Object.entries
, nous avons exploré bien plus que le simple parcours clé-valeur. Ces méthodes ouvrent des possibilités fascinantes pour manipuler des données complexes : filtrage, enrichissement, transformation… Ce sont des techniques qui, lorsqu’elles sont maîtrisées, rendent nos applications plus dynamiques et de manière plus souples.
Conclusions
Nous avons exploré une alternative pour parcourir un objet JavaScript, en passant d’une boucle classique à une méthode moderne et performante avec Object.entries
. Ces outils et techniques sont essentiels pour naviguer dans des structures complexes et les transformer en interfaces utilisateur claires et interactives.