Avant que includes n'existe, toute vérification de présence passait par indexOf et une comparaison à -1. La méthode est restée, parce qu'elle répond à une autre question : non pas si la valeur est là, mais où elle est.
Et ce -1, choisi comme signe d'absence, mérite qu'on s'y arrête.
Définition
indexOf rend l'index de la première occurrence d'une valeur, ou -1 si elle ne s'y trouve pas. Il fonctionne sur un Array (tableau) comme sur une String (chaîne de caractères).
const langues = ["fr", "en", "es"];
console.log(langues.indexOf("en")); // 1
console.log(langues.indexOf("de")); // -1
const chemin = "/fr/formations/formation-javascript";
console.log(chemin.indexOf("/formations")); // 3
console.log(chemin.slice(chemin.indexOf("formation-"))); // "formation-javascript"La dernière ligne montre l'usage qui justifie encore la méthode : découper une chaîne à partir d'un repère, ce que includes ne permet pas puisqu'il ne rend qu'un booléen.
Le piège du zéro
Une valeur trouvée en première position rend 0, qui est une valeur Truthy et falsy fausse. Tester le résultat comme une condition inverse alors la logique.
const roles = ["ROLE_ADMIN", "ROLE_USER"];
if (roles.indexOf("ROLE_ADMIN")) {
console.log("jamais affiché"); // l'index vaut 0, donc la condition est fausse
}
if (roles.indexOf("ROLE_ADMIN") !== -1) {
console.log("correct");
}La comparaison explicite à -1 n'est pas facultative. Quand seule la présence vous intéresse, includes() supprime le problème à la racine en rendant directement un booléen.
Les trois méthodes de recherche
| Méthode | Ce qu'elle cherche | Ce qu'elle rend |
|---|---|---|
indexOf(valeur) | Une valeur exacte | Un index, ou -1 |
lastIndexOf(valeur) | La même, en partant de la fin | Un index, ou -1 |
findIndex(fonction) | Le premier élément qui passe un test | Un index, ou -1 |
Les trois colonnes se lisent ensemble : la méthode, ce qu'elle prend, ce qu'elle rend. La comparaison des deux premières suit l'Égalité stricte (===), donc un objet ne s'y trouve jamais par son contenu. C'est le rôle de findIndex, qui reçoit une fonction et compare ce que vous voulez.
Questions fréquentes
Pourquoi -1 plutôt que undefined ?
Parce que la méthode rend toujours un nombre, et que -1 est le seul index impossible dans un tableau. Le choix vient des premières versions du langage et n'a jamais changé, par souci de compatibilité. Les méthodes plus récentes comme Array.find() rendent bien undefined.
Comment trouver toutes les occurrences ?
En relançant la recherche après chaque trouvaille, grâce au second argument qui fixe le point de départ : let i = texte.indexOf("a"); while (i !== -1) { positions.push(i); i = texte.indexOf("a", i + 1); }. Oublier le + 1 produit une boucle infinie, puisque la même position est retrouvée à chaque tour.
Pourquoi indexOf ne trouve-t-il pas NaN ?
Parce qu'il compare avec ===, et que NaN === NaN vaut false par définition. Un tableau contenant NaN rend donc -1. includes() utilise une comparaison légèrement différente et le trouve, ce qui est l'un des rares cas où les deux méthodes divergent.