Vérifier si une chaîne en contient une autre (recherche de sous-chaîne) reste l'une des opérations sur les chaînes les plus courantes dans le développement JavaScript. Qu'il s'agisse de valider la saisie d'un utilisateur, d'implémenter des filtres de recherche dans des applications React/Vue, d'analyser des réponses d'API, de construire des fonctionnalités d'autocomplétion ou de traiter des journaux dans Node.js, cette vérification apparaît partout.
En février 2026, ECMAScript 2026 (ES2026) est la norme actuelle ou imminente (finalisée à la mi-2026). Le noyau String.prototype méthodes de détection des sous-chaînes - includes(), indexOf(), search(), et les expressions rationnelles .test() - restent inchangées depuis ES2015/ES6. Aucune nouvelle méthode majeure de recherche de chaînes de caractères n'a été introduite dans ES2025 ou ES2026 ; l'accent reste mis sur les performances, la lisibilité, la correction Unicode et les meilleures pratiques modernes dans des moteurs tels que V8 (Node 22+/Chrome 130+), SpiderMonkey (Firefox 135+) et JavaScriptCore (Safari 19+).
Ce guide couvre toutes les techniques pratiques, les réalités des performances en 2026, les cas limites, les considérations de sécurité et les recommandations prêtes pour la production.
Pourquoi les vérifications de chaînes de caractères sont omniprésentes
- UI/UX: Recherche en direct, filtrage des balises, validation des formulaires
- Back-end: Analyse du journal, recherche d'itinéraires, modération du contenu
- Traitement des données: Filtrer des tableaux de chaînes/objets
- Sécurité: Détection de schémas malveillants (charges utiles XSS, mots interdits)
- Sensible aux performances: Autocomplétion (millions de vérifications/sec), suivi en temps réel
Les petites inefficacités se multiplient rapidement dans les boucles ou les grands ensembles de données.
1. Norme moderne : String.prototype.includes()
La méthode de référence depuis ES2015 - propre, révélatrice d'intentions et fortement optimisée.
Signature
js str.includes(searchString, position ?)
searchString :sous-chaîne à trouver (transformée en chaîne de caractères ; RegExp lance)position(optionnel) : indice de départ (par défaut 0 ; clampé ≥0)
Retours: booléen
Exemples
js
const phrase = "JavaScript en 2026 est puissant et rapide" ;
console.log(phrase.includes("2026")) ; // vrai
console.log(phrase.includes("2025")) ; // faux
console.log(phrase.includes("script")) ; // vrai (sensible à la casse)
console.log(phrase.includes("")) ; // true ← empty correspond toujours
console.log(phrase.includes("fast", 30)) ; // vrai
console.log(phrase.includes("fast", 40)) ; // fauxPourquoi préférer inclut() en 2026 ?
- Lisibilité maximale : exprime clairement “contient-il ?”.”
- Optimisation du moteur (V8/SpiderMonkey utilisent des algorithmes rapides de Boyer-Moore ou des algorithmes bidirectionnels)
- Support universel : 100% dans les navigateurs modernes/Node depuis ~2017
Inconvénients
- Uniquement booléen (pas d'index)
- Toujours sensible à la casse
2. Classique et conscient de la position : String.prototype.indexOf()
Le cheval de bataille d'avant l'ES6 - toujours excellent lorsque vous avez besoin de l'emplacement.
Signature
js str.indexOf(searchString, fromIndex ?)
Retours: premier indice ≥ fromIndex ou -1
Contrôle d'existence
js
if (phrase.indexOf("2026") !== -1) { /* trouvé */ }
// Style préféré :
if (phrase.indexOf("2026") >= 0) { /* trouvé */ }Recherche de toutes les occurrences
js
let positions = [] ;
let idx = -1 ;
while ((idx = phrase.indexOf("a", idx + 1)) !== -1) {
positions.push(idx) ;
}
console.log(positions) ; // [1, 4, 11, ...]2026 réalité: inclut() et indexOf() ont une vitesse quasi identique pour les contrôles booléens - choisissez inclut() pour plus de clarté, à moins que vous n'ayez besoin de l'index.
3. Contrôles insensibles à la casse (besoin le plus fréquent dans le monde réel)
Il n'existe pas d'indicateur natif d'insensibilité à la casse pour includes()/indexOf().
Meilleure pratique 2026 : normaliser les cas
js
function containsIgnoreCase(text, term) {
if (text == null || term == null) return false;
return text.toLowerCase().includes(term.toLowerCase());
// Ou locale-aware (recommandé pour la production) :
// text.toLocaleLowerCase('en').includes(term.toLocaleLowerCase('en')) ;
}
console.log(containsIgnoreCase(phrase, "POWERFUL")) ; // vraiPourquoi toLowerCase() gagne généralement
- Plus rapide que les expressions rationnelles pour les recherches littérales
- Les cordes temporaires sont bon marché dans les CG modernes
- Évite la surcharge liée à la compilation et à l'échappement des expressions rationnelles
Précaution locale - Turc ("I".toLowerCase() → "ı") ou d'autres langues peuvent surprendre. Utiliser toLocaleLowerCase() avec une locale explicite lorsque l'internationalisation est importante.
Alternative Regex (Flexible mais plus lent)
js
function containsIgnoreCaseRegex(text, term) {
if (!term) return true ;
// Échapper aux caractères spéciaux si le terme provient de l'utilisateur
const escaped = term.replace(/[.*+?^${}()|[\]\]/g, '\$&') ;
return new RegExp(escaped, 'i').test(text) ;
}Ou one-liner (terme de confiance uniquement) :
js /2026/i.test(phrase) ; // vrai
Quand choisir les expressions rationnelles
- Nécessité de délimiter les mots (
\bterm\b) - Alternance (
chat|chien) - Solutions de contournement ou autres modèles
Conseil de performance: Compiler les expressions rationnelles une fois boucles extérieures/chemins chauds.
4. Autres méthodes et quand les utiliser
String.prototype.search(regexp)
Renvoie l'index de la première correspondance ou-1. Rarement utilisé aujourd'hui -inclut()ou.test()sont plus claires.String.prototype.match()/matchAll()
Il s'agit d'extraire des correspondances et non d'une simple existence.startsWith()/endsWith()(ES2015)
Contrôles spécialisés - plus rapides pour les préfixes/suffixes.
js
phrase.startsWith("Java") ; // vrai
phrase.endsWith("rapide") ; // vrai5. Performances des moteurs 2026
Vitesses relatives approximatives (V8/Node 22+, grande chaîne ~10k chars, recherche littérale) :
| Méthode | Rel. Vitesse | Meilleur pour | Notes |
inclut() littéral | 1.0× | Simple oui/non | Premier choix |
indexOf() | ~1.0-1.02× | Besoin d'un index ou d'une recherche multiple | La même famille que comprend |
toLowerCase() + includes() | 0.65-0.80× | Littéral insensible à la casse | Deux cordes temporaires mais rapides |
/literal/i.test() | 0.25-0.45× | Cas-insens. ou limites | Tête de pont des expressions rationnelles |
new RegExp(escaped, 'i').test() | 0.20-0.40× | Entrée dynamique/assainie | Coût d'évasion + regex |
Principaux enseignements: Utilisation inclut() pour les littéraux. Normaliser la casse pour ignorer la casse, à moins que les fonctions de regex ne soient nécessaires. Les expressions rationnelles sont 2 à 5 fois plus lentes, mais elles sont acceptables, sauf dans les boucles étroites.
6. Cas marginaux et problèmes (critiques en 2026)
includes("") → true(la sous-chaîne vide correspond à tout)nul/indéfinibotte de foin/aiguille → TypeError- Paires de substituts et emojis → traités correctement (UTF-16)
js "Hello 🌍 2026".includes("🌍") ; // true - Négatif
position →traité comme 0 - Chaînes très longues → les moteurs utilisent des algorithmes efficaces (en moyenne O(n))
- Entrée de l'utilisateur → jamais construire des expressions rationnelles à partir de chaînes de caractères brutes sans les escamoter
7. Aides à la production et bonnes pratiques
Utilitaire à sécurité nulle (adapté à TypeScript) :
ts
function contains(
haystack: string | null | undefined,
needle: string | null | undefined,
options: { ignoreCase?: boolean; from?: number } = {}
): boolean {
if (haystack == null || needle == null) return false;
const { ignoreCase = false, from = 0 } = options;
const h = ignoreCase ? haystack.toLowerCase() : haystack;
const n = ignoreCase ? needle.toLowerCase() : needle;
return h.includes(n, from);
}
// Usage
contains("JavaScript 2026", "script", { ignoreCase: true }); // true2026 Recommandations
- Par défaut
inclut()pour plus de clarté - Normaliser la casse au lieu d'une expression rationnelle pour un simple ignore-case
- Mise en cache des motifs d'expressions rationnelles
- Mesurer des charges de travail réelles (éviter l'obsession des micro-benchmarks)
- Utiliser des bibliothèques (lodash
_.inclut, Fuse.js) uniquement lorsque vous avez besoin d'une recherche floue/avancée
Conclusion
En 2026, vérifier si une chaîne contient une sous-chaîne en JavaScript reste une opération d'une simplicité déconcertante qui s'appuie sur des API très optimisées. String.prototype.includes() reste le choix préféré pour la plupart des scénarios, car il offre clarté, performance et lisibilité expressive. Pour les contrôles insensibles à la casse, la normalisation avec toLowerCase() (ou d'autres solutions tenant compte des spécificités locales, le cas échéant) constitue une approche fiable et efficace. Les expressions régulières doivent être réservées aux situations nécessitant une flexibilité au niveau des motifs allant au-delà de la correspondance littérale.
Les développeurs s'appuient sur des modèles communs :
- Vérification booléenne littérale →
str.includes(sub) - Avec position/index →
str.indexOf(sub) >= 0 - Ignorer le cas →
str.toLowerCase().includes(sub.toLowerCase()) - Besoins complexes → En cache
RegExp.test()
La sélection de la méthode appropriée et la prise en compte des cas extrêmes - tels que les valeurs vides, les entrées nulles, la gestion de l'Unicode et les données générées par l'utilisateur - garantissent un code à la fois résilient et évolutif.
Carmatec aide les entreprises à créer des applications JavaScript de haute performance où l'attention portée à ces détails fondamentaux contribue directement à la fiabilité, à la rapidité et à la maintenabilité à grande échelle.