JavaScript - Les tableaux

Les tableaux sont des structures bien particulières en JavaScript, et très utilisées : ils permettent de stocker, transformer et filtrer des listes de données très simplement.

Déclarer un tableau

Un tableau se déclare de la manière suivante :

const monTableau = [];  

Ici, je déclare un tableau vide.

Mais il est également possible de déclarer un tableau avec des données dedans :

const monTableau = [12,13, 81, 0, -16];

De même, comme JavaScript n’est pas un langage fortement typé, un tableau peut stocker des données de différents types :

const monTableau = [
	'toto', 
	12, 
	true, 
	false, 
	{username: 'jdoe'}, 
	[
		null, 
		undefined, 
		13
	]
];

Ici, je stocke des nombres, des chaînes de caractères, des booléens, un objet, null, undefined, et même un autre tableau !

Le prototype Array

Les tableaux héritent du prototype Array : cela signifie donc qu’ils ont des propriétés et des méthodes, que nous allons voir maintenant.

La propriété length

Un tableau possède une longueur, qui peut être consultée avec la propriété length.

Exemple :

const t = [1, 2, 3];
console.log(t.length); // affichera 3

Cette propriété est read-write : cela signifie qu’elle permet également de supprimer des éléments du tableau.

Exemple :

const t = [1, 2, 3];
t.length = 1;
console.log(t); // affichera [1];

Les méthodes

Ajouter des données - push

https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/push.

La méthode push permet d’ajouter des données à un tableau. Elle prend en paramètre un nombre indéfini d’arguments, et les ajoute au tableau.

Exemple :

const t = [1, 2, 3];
t.push(4, 5, 6);
console.log(t); // affichera [1, 2, 3, 4, 5, 6]

La boucle forEach

https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/foreach

Cette méthode permet d’exécuter une fonction sur tous les éléments d’un tableau. Elle prend en paramètre une callback (une fonction).

La syntaxe est la suivante :

function displayName(name) {
	console.log(name);
}

const t = ['Achraf', 'Coumba', 'Wacil', 
'Antony', 'Joshua', 'Samy', 'Lucas'];

t.forEach(displayName);

Ici, vous voyez que je crée un tableau comportant des prénoms. Puis, juste après, j’appelle la méthode forEach en luis passant une fonction : la fonction displayName.

Vous remarquez également que, lorsque je passe la fonction displayName, je ne mets pas de parenthèses.

En effet, si j’écrivais

t.forEach(displayName());

Mon code ne fonctionnerait pas : d’abord, la fonction displayName serait appelée, et son résultat serait ensuite passé à la méthode forEach. Comme elle ne retourne rien, t.forEach() recevrait undefined et déclencherait une erreur.

Une manière parfois plus compréhensible de l’écrire est :

function displayName(name) {
	console.log(name);
}

const t = ['Achraf', 'Coumba', 'Wacil', 
'Antony', 'Joshua', 'Samy', 'Lucas'];

t.forEach((value) => {
	displayName(value)
});

Sous ses airs un peu compliqués, cette syntaxe est en réalité très simple : ici, entre les parenthèses du forEach, nous passons simplement une fonction :

(value) => {
	displayName(value);
}

Cette fonction est anonyme et sera exécutée à chaque tour de boucle.

Exercice

Dans l’exemple suivant, faites en sorte de n’afficher QUE les nombres pairs du tableau :

function displayNumber(number) {
	console.log(number);
}

const t = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

Le mapping de données - map

https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/map.

S’il est possible de parcourir un tableau, il est également possible d’en créer un nouveau avec des données transformées : c’est ce que permet de faire la méthode map !

Elle fonctionne comme suit :

const t = [1, 2, 3, 4, 5, 6];
const u = t.map((x) => {
	return x * 2;
});

console.log(u); // affichera [2, 4, 6, 8, 10, 12]

Ici, la méthode map a reçu en paramètre une callback, qui, pour tout élément du tableau t, a retourné cet élément multiplié par 2. Cela a retourné un nouveau tableau, ce qui signifie que le tableau de base est resté intact.

Exercice 1

À partir du tableau suivant, utilisez la fonction map pour créer un nouveau tableau de nombres élevés au carré.

const t = [1, 2, -6, -100, 46, 30];

Exercice 2

À partir du tableau suivant, utilisez la fonction map pour créer un nouveau tableau ne comportant que des chaînes de caractère.

const t = [1, 2, -6, -100, 46, 30];

Exercice 3

À partir du tableau suivant, utilisez la fonction map pour créer un nouveau tableau ne comportant que le nom et le prénom des utilisateurs.

const users = [
	{firstname: 'Armand', lastname: 'LOISELIER', age: 35},
	{firstname: 'Priya', lastname: 'KANDASAMI', age: 28},
	{firstname: 'Emmanuelle', lastname: 'REHANNA', age: 30},
	{firstname: 'Yzar', lastname: 'COHEN', age: 54},
	{firstname: 'Ahmed', lastname: 'SADAOUI', age: 23},
];

Exercice 4

À partir du tableau suivant, utilisez la fonction map pour créer un tableau comportant les noms et prénoms dans des <h1></h1>, et les métiers dans des <h2></h2>.

const members = [
	{firstname: 'Jessica', lastname: 'BOUTEILLER', job: 'Digital Content Marketing'},
	{firstname: 'Robin', lastname: 'LANAUD', job: 'Coffee Technical Officer'},
	{firstname: 'Antony', lastname: 'LANGLOIS', job: 'In The Sauce'},
	{firstname: 'Thomas', lastname: 'TOLEDO', job: 'Sauce Chief'},
	{firstname: 'Olivier', lastname: 'KRAKUS', job: 'Sauce Chief'},
];

/**
Résultat attendu :

[
	'<h1>Jessica BOUTEILLER</h1><h2>Digital Content Marketing</h2>',
	'<h1>Robin LANAUD</h1><h2>Coffee Technical Officer</h2>',
	'<h1>Antony LANGLOIS</h1><h2>In The Sauce</h2>',
	'<h1>Thomas TOLEDO</h1><h2>Sauce Chief</h2>',
	'<h1>Olivier KRAKUS</h1><h2>Sauce Chief</h2>',
]
**/

Filtrer des données - filter

https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/filter.

Il peut arriver que l’on veuille filtrer des données avant d’effectuer des traitement dessus. Pour cela, la méthode filter va grandement nous aider.

Voici comment cette méthode fonctionne :

const fruits = [
	{title: 'banana', stock: 1200, price: '0.5'},
	{title: 'orange', stock: 0, price: '2'},
	{title: 'kiwi', stock: 800, price: '1.3'},
	{title: 'mango', stock: 0, price: '3'},
]

const fruitsInStock = fruits.filter((fruit) => {
	return fruit.stock > 0;
});

Dans cet exemple, nous avons un tableau contenant des objets représentant des stocks de fruits. Nous souhaitons récupérer la liste des fruits ayant un stock supérieur à 0. Pour cela, la méthode filter prend en paramètre une callback qui doit retourner un booléen.

À chaque tour de boucle, si le booléen est true, alors l’élément est gardé dans le nouveau tableau qui est en train d’être créé, et sinon il est ignoré.

Exercice 1

Utilisez la méthode filter pour ne récupérer que les utilisateurs dont le nom d’utilisateur, le prénom ou bien le nom de famille contiennent la chaîne de caractère 'e'.

Pour cela, aidez-vous de la méthode includes du prototype String : https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/String/includes.

const users = [
	{firstname: 'Hoani', lastname: 'PRIAM', username: 'hpriam'},
	{firstname: 'Jules', lastname: 'DELTEIL', username: 'jdelteil'},
	{firstname: 'Imène', lastname: 'BENDACHA', username: 'ibendacha'},
	{firstname: 'Thomas', lastname: 'BONALDI', username: 'tbonaldi'},
	{firstname: 'Thomas', lastname: 'GEOFFROY', username: 'tgeoffroy'},
	{firstname: 'Justine', lastname: 'QUERE', username: 'jquere'},
	{firstname: 'Shelly', lastname: 'LAGZIEL', username: 'slagziel'},
	{firstname: 'Pyanossa', lastname: 'NDENGWE', username: 'pndengwe'},
	{firstname: 'Benoit', lastname: 'OLIFIRENKOFF', username: 'bolifirenkoff'},
];

Exercice 2

Partez du même tableau que précédemment, et faites en sorte que le filtrage fonctionne pour n’importe quelle chaîne de caractères.

Pour cela, écrivez une fonction searchUser, qui prendra en paramètre un argument value et un argument users (qui sera un tableau d’utilisateurs), et retournera un nouveau tableau filtré.

Réduire un tableau à un seul élément - reduce

https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce.

Cette méthode est sans doute la moins intuitive : pourtant, elle est très pratique et, une fois comprise, vous adorerez l’utiliser.

La syntaxe est la suivante :

const t = [10, 20, 30, 40, 50];
const sum = t.reduce((accumulator, currentValue) => {
	return currentValue + accumulator;
}, 0);

Ici, nous avons un tableau de nombres. Nous utilisons la méthode reduce pour transformer ce tableau de nombre en une seule valeur.

Analysons la callback :

(accumulator, currentValue) => {
	return currentValue + accumulator;
}

Elle prend deux arguments, que j’ai appelé currentValue et accumulator. Elle retourne la somme des deux arguments.

Mais que valent currentValue et accumulator ?

En fait, à chaque tour de boucle, currentValue va prendre la valeur de l’élément courant dans le tableau. Donc, au premier tour de boucle, currentValue vaudra 10, puis au deuxième elle vaudra 20, et ainsi de suite jusqu’à 50.

L’argument accumulator, quant à lui, sera égal au résultat cumulé des tours précédents. Donc, au premier tour de boucle, il vaudra 0, puis au deuxième il vaudra 10, au troisième 30, au quatrième 60, et au cinquième 100.

Ainsi, à chaque tour de boucle, on accumule les valeurs dans une variable, et on retourne le résultat final.

Exercice

À partir du tableau suivant, retournez le produit de tous les nombres du tableau.

const t = [1, 2, 3, 4, 5];

Le résultat devrait être 1*2*3*4*5 = 120.

Exercice

Faites de même, mais en faisant attention à ce que les valeurs nulles ne soient pas prises en compte.

const t = [1, 29, 63, 7, 2, 0, 0, 32, 0, 23, -1];

Le résultat devrait être -18 825 408

Les prédicats some et every

Il est également possible de vérifier qu’un tableau contient ou non certaines valeurs, avec les prédicats some et every.

  • every va vérifier que tous les éléments d’un tableau vérifient une ou plusieurs conditions ;
  • some va vérifier qu’au moins un élément va vérifier une ou plusieurs conditions.

Exemple :

const t = [1, 2, 3, 4, 5];

const hasAtLeastOneEvenNumber = t.some((x) => {
	return x % 2 === 0;
});

const hasNoZero = t.every((x) => {
	return x !==0;
});

Copier des tableaux

Très souvent, nous sommes amenés à copier des tableaux ou encore à les concaténer. Pour cela, il existe deux notations.

La méthode concat

https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/concat

La méthode concat du prototype Array permet de concaténer deux tableaux en un seul :

const t = [1, 2, 3, 4];
const u = [4, 5, 6, 8];

const v = t.concat(u);
console.log(v); // [1, 2, 3, 4, 5, 6, 7, 8]

Le spread operator

Il s’agit d’une notation plus concise, très utilisée aujourd’hui :

const t = [1, 2, 3, 4];
const u = [4, 5, 6, 8];

const v = [...t, ...u];
console.log(v); // [1, 2, 3, 4, 5, 6, 7, 8]

La différence ici, est qu’au lieu d’utiliser concat, je crée un tableau [], dans lequel je vais mettre le contenu de t et le contenu de u. Pour ce faire, j’utilise le spread operator, qui est représenté par trois points de suspension ... juste avant chaque tableau.

Vous pouvez voir cela comme le fait de “dézipper” un tableau et de placer les un après les autres les éléments qui le composent.

Trouver un élément - find

https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/find

La méthode find permet de trouver un élément dans un tableau, selon une condition.

Elle prend en paramètre une callback qui doit retourner true ou false.

Exemple :

const users = [
	{username: 'toto'},
	{username: 'toto2'},
	{username: 'tata'},
	{username: 'titi'},
	{username: 'tutu'},
]

const userToto = users.find((user) => {
	return user.username.includes('toto');
});

Dans cet exemple, nous avons un tableau d’utilisateurs. Nous souhaitons récupérer l’utilisateur qui a un username contenant "toto". Pour cela, nous appelons la méthode find en lui passant une callback, qui prendra en paramètre un user, et qui retournera true si son username contient "toto", false sinon.

Dans le tableau, cependant, il existe deux utilisateurs dont le username contient cette chaîne de caractères : en fait, la méthode find s’arrête au premier élément vérifiant la condition.

Trier un tableau

https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

La méthode sort permet de trier des tableaux.

Elle prend en paramètre une callback qui va retourner trois valeurs :

  • une valeur > 0 ;
  • une valeur < 0 ;
  • la valeur 0.

Voici un exemple :

const t = ['b', 'c', 'd', 'a'];
const sorted = t.sort((x, y) => {
	if (x > y) {
		return 1;
	} else if (x < y) {
		return -1;
	} else {
		return 0;
	}
});

Ici, la callback passée en paramètre à la méthode sorted doit prendre deux arguments (que j’ai arbitrairement nommé x et y). J’ai également et volontairement utilisé une écriture exhaustive pour que l’on comprenne bien ce qu’il se passe.

La méthode sort va, à chaque tour, comparer ce que l’on appelle un tuple (une paire) de valeurs du tableau : si le premier élément doit être placé après le deuxième, on doit renvoyer une valeur supérieure à zéro, s’il doit être placé avant, on doit renvoyer une valeur inférieure à zéro. Si les deux éléments sont égaux, on doit renvoyer zéro.

Cela vaut pour un ordre ascendant. Pour un ordre descendant, c’est l’inverse.

Pour vous en assurer, exécutez le code suivant :

const t = ['b', 'c', 'd', 'a'];
const sorted = t.sort((x, y) => {
	if (x > y) {
		console.log(`${x} > ${y}`);
		return 1;
	} else if (x < y) {
		console.log(`${x} < ${y}`);
		return -1;
	} else {
		console.log(`${x} === ${y}`);
		return 0;
	}
});

Vous verrez alors qu’à chaque comparaison, on retourne les valeurs énoncées précédemment.

Sachant cela, il est possible de réduire la notation précédente au profit de celle-ci :

const t = ['b', 'c', 'd', 'a'];
const sorted = t.sort((x, y) => {
	return x - y;
});

Attention ! La méthode sort modifie directement le tableau et n’en crée pas de nouveau !

Inverser un tableau - reverse

https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse

La méthode reverse permet tout simplement d’inverse l’ordre d’un tableau.

const t = [1, 2, 3, 4];

const reversed = t.reverse();

Attention ! La méthode reverse modifie directement le tableau et n’en crée pas de nouveau !

Conclusion

Il existe d’autres méthodes pour le prototype Array. Celles que nous avons vu pour le moment seront suffisantes pour la suite des cours, et constituent déjà une base importante pour mener à bien nos développements.