Adloun

Tableaux et objets

Cours · JavaScript : rendre le Web interactif (école d'ingénieur), chapitre 5 · école d'ingénieur, informatique · le début du chapitre, la suite sur Adloun

La Librairie du Campus manipule sans cesse des collections : la liste des livres du catalogue, les lignes d'un panier, les rayons, les auteurs. Et chaque livre est lui-même un petit paquet de données : un titre, un auteur, un rayon, un prix. En Java, on aurait écrit une classe Livre et une ArrayList<Livre>. En JavaScript, on commence plus simplement : un tableau d'objets littéraux, écrits directement entre crochets et accolades, sans déclarer de type.

Ce chapitre présente ces deux structures et les outils qui les accompagnent : les méthodes de tableau qui remplacent la plupart des boucles (map, filter, reduce…), le tri et son comparateur, les objets et leurs propriétés, la déstructuration, les collections Map et Set, et le format JSON qui sert à échanger tout cela avec un serveur. Il insiste sur une notion que Java connaît déjà mais qui surprend toujours : tableaux et objets sont manipulés par référence.

Objectifs du chapitre

  • Créer, lire et modifier un tableau ; le parcourir avec for...of.
  • Transformer une collection avec map, filter, find, some, reduce, et les enchaîner.
  • Trier correctement : comparateur numérique, localeCompare, tri qui modifie ou non le tableau.
  • Créer et manipuler des objets littéraux ; distinguer référence et copie, copie superficielle et profonde.
  • Utiliser la déstructuration, la décomposition ..., Map, Set et JSON.

Tous les programmes du chapitre sont dans code/ch5/ ; on les exécute avec Node.js :


$ node tableaux.mjs

Node affiche les tableaux et les objets sous une forme un peu différente de la console du navigateur (guillemets simples, espaces entre crochets), mais les valeurs sont les mêmes.

5.1 Les tableaux

Un tableau s'écrit entre crochets. Contrairement au tableau Java, il n'a pas de taille fixe ni de type d'élément : il grandit et rétrécit à la demande, comme une ArrayList.


const titres = ["Programmation Java", "Analyse MPSI", "Le Petit Prince"];

console.log(titres.length);
console.log(titres[0]);
console.log(titres.at(-1));
console.log(titres[5]);

titres.push("L’Étranger");
console.log(titres);
const retire = titres.shift();
console.log(retire, titres.length);
console.log(titres.includes("Analyse MPSI"), titres.indexOf("Physique"));

3
Programmation Java
Le Petit Prince
undefined
[
  'Programmation Java',
  'Analyse MPSI',
  'Le Petit Prince',
  'L’Étranger'
]
Programmation Java 3
true -1

Un tableau déclaré const se modifie

const titres = [...] interdit de réaffecter la variable titres à un autre tableau, pas de modifier le tableau lui-même : titres.push(...) est permis. C'est le final de Java : la référence est constante, l'objet ne l'est pas.

5.1.1 Parcourir

La boucle for...of donne chaque élément ; forEach appelle une fonction pour chaque élément, avec en second argument son indice.


const prix = [32, 89, 45, 59, 8.5, 7.9];

for (const p of prix) {
  if (p > 50) {
    console.log("cher :", p);
  }
}

prix.forEach((p, i) => console.log(i, p));

cher : 89
cher : 59
0 32
1 89
2 45
3 59
4 8.5
5 7.9

On préfère for...of : on peut en sortir avec break ou return, et il fonctionnera avec await au chapitre 9. La boucle for...in, elle, parcourt les noms des propriétés d'un objet : sur un tableau, elle donne les indices sous forme de chaînes. Ne l'utilisez pas sur un tableau.

5.2 Transformer une collection

Au chapitre 4, nous avons vu qu'une fonction peut en recevoir une autre en argument. Les tableaux en tirent une famille de méthodes qui remplacent la plupart des boucles écrites à la main : on dit ce que l'on veut, pas comment le calculer. C'est l'équivalent des streams de Java (stream().map(...).filter(...)), sans stream() ni collect.

Définition 5.1Méthodes de parcours

Chacune reçoit une fonction appelée avec l'élément (puis son indice) :

  • map(f) : nouveau tableau des f(x), de même longueur ;
  • filter(f) : nouveau tableau des éléments pour lesquels f(x) est vrai ;
  • find(f) : le premier élément qui convient, ou undefined ; findIndex(f) : sa position, ou ;
  • some(f) : au moins un convient ? every(f) : tous conviennent ?
  • reduce(f, initial) : accumule une valeur unique, en appelant f(accumulateur, x).

Aucune de ces méthodes ne modifie le tableau d'origine.


const livres = [
  { titre: "Programmation Java", rayon: "Informatique", prix: 32 },
  { titre: "Introduction à l’algorithmique", rayon: "Informatique", prix: 89 },
  { titre: "Analyse MPSI", rayon: "Mathématiques", prix: 45 },
  { titre: "Le Petit Prince", rayon: "Littérature", prix: 8.5 },
];

const titres = livres.map((livre) => livre.titre);
console.log(titres);

const informatique = livres.filter((livre) => livre.rayon === "Informatique");
console.log(informatique.length);

const premierBonMarche = livres.find((livre) => livre.prix < 10);
console.log(premierBonMarche.titre);
console.log(livres.find((livre) => livre.prix > 100));

console.log(livres.some((livre) => livre.prix > 50), livres.every((livre) => livre.prix > 5));
console.log(livres.findIndex((livre) => livre.rayon === "Mathématiques"));

[
  'Programmation Java',
  'Introduction à l’algorithmique',
  'Analyse MPSI',
  'Le Petit Prince'
]
2
Le Petit Prince
undefined
true true
2

Les éléments du tableau livres sont des objets littéraux (section 5.4) ; livre.titre lit la propriété titre. Remarquez la recherche qui échoue : find rend undefined sans erreur, et c'est l'accès suivant, .titre, qui échouerait.

5.2.1 Accumuler une valeur

reduce est la plus générale : elle part d'une valeur initiale et la fait évoluer élément après élément. Le total d'un panier en est l'exemple type.


const panier = [
  { titre: "Programmation Java", prix: 32, quantite: 2 },
  { titre: "Le Petit Prince", prix: 8.5, quantite: 3 },
];

const total = panier.reduce((somme, ligne) => somme + ligne.prix * ligne.quantite, 0);
console.log(total);

const nombreDeLivres = panier.reduce((n, ligne) => n + ligne.quantite, 0);
console.log(nombreDeLivres);

// Chaînage : les titres des lignes de plus de 20 €, en majuscules.
const gros = panier
  .filter((ligne) => ligne.prix * ligne.quantite > 20)
  .map((ligne) => ligne.titre.toUpperCase());
console.log(gros);

89.5
5
[ 'PROGRAMMATION JAVA', 'LE PETIT PRINCE' ]

Déroulons le premier reduce : l'accumulateur vaut d'abord 0 ; après la première ligne, ; après la seconde, . Le dernier exemple enchaîne deux méthodes : chacune rend un nouveau tableau, sur lequel on appelle la suivante.

La suite du cours est sur Adloun

Le chapitre en entier, formules et figures comprises, avec le tuteur, les fiches, les QCM et les exercices.

Lire la suite du cours

En accès libre, sans inscription.

Exercices corrigés de ce chapitre

Lire la suite du cours →