Parcourir un tableau pour faire quelque chose de chaque élément, écrire une ligne de journal, envoyer un message, mettre à jour l'affichage : voilà le seul emploi de forEach.
Il ne construit rien et ne renvoie rien. C'est à la fois sa simplicité et sa limite.
Définition
forEach est une méthode d'Array (tableau) qui appelle une fonction sur chaque élément, dans l'ordre, et rend undefined. Ce que la fonction renvoie est ignoré.
const articles = ["clavier", "souris"];
const retour = articles.forEach((a, i) => console.log(i, a));
// 0 clavier
// 1 souris
console.log(retour); // undefinedCette valeur de retour interdit tout enchaînement. Écrire articles.forEach(...).filter(...) lève une TypeError, puisque la méthode est alors appelée sur undefined. Une chaîne de traitements passe donc par Array.map() et Array.filter().
Ce qu'il ne sait pas faire
break et continue n'ont aucun sens à l'intérieur : ils appartiennent aux boucles, pas aux fonctions. Un return dans le corps quitte seulement le tour en cours, exactement comme un continue.
// Sortir en cours de route demande une vraie boucle
for (const n of [1, 2, 3]) {
if (n === 2) break;
console.log(n); // 1
}Quand l'objectif est justement de s'arrêter tôt, deux méthodes le font d'elles-mêmes : Array.some() interrompt au premier succès, Array.find() rend l'élément trouvé et cesse le parcours.
Le piège de l'attente
Une fonction async rend une Promise, et forEach jette ce que la fonction renvoie. Il ne l'attend donc jamais.
const attendre = (ms) => new Promise((ok) => setTimeout(ok, ms));
async function envoyer(ids) {
ids.forEach(async (id) => {
await attendre(10);
console.log("envoyé", id);
});
console.log("terminé"); // s'affiche AVANT les envois
}La ligne « terminé » sort la première, et une erreur survenue dans un envoi ne remonte nulle part. Pour attendre réellement, il faut une boucle of avec await, ou Promise.all sur un Array.map() lorsque les envois sont indépendants.
Questions fréquentes
forEach ou for...of ?
La boucle for...of accepte break, continue et await, ce qui en fait le choix par défaut le plus sûr. forEach garde l'avantage de la brièveté sur une action courte, dans une chaîne où l'on veut rester en style fonctionnel.
Parcourt-il les cases vides d'un tableau ?
Non, il les saute. Sur [1, , 3], la fonction est appelée aux positions 0 et 2 seulement, et la case du milieu est ignorée sans avertissement. Ces tableaux à trous sont rares mais apparaissent après un delete ou une affectation au-delà de la fin.
Peut-on modifier le tableau pendant le parcours ?
Techniquement oui, mais le nombre de tours est fixé au départ : les éléments ajoutés en route ne sont jamais visités, et une suppression décale les suivants, qui se retrouvent alors sautés. Construisez plutôt un nouveau tableau.