`Objet` « String »
Cet article explique l'objet String.
L'explication couvre tout, des bases aux techniques avancées, y compris les pièges liés à Unicode et aux expressions régulières, étape par étape et de manière facile à comprendre.
YouTube Video
Objet « String »
Les chaînes de caractères en JavaScript sont l’un des types les plus fréquemment utilisés dans le développement quotidien.
Différence entre les chaînes primitives et les objets String
Les chaînes primitives (comme "hello") se comportent différemment des objets enveloppe tels que new String("hello"). Normalement, vous devriez utiliser les chaînes primitives, et il y a peu de raisons d’utiliser la forme objet.
1// Primitive string
2const a = "hello";
3
4// String wrapper object
5const b = new String("hello");
6
7console.log(typeof a); // "string"
8console.log(typeof b); // "object"
9console.log(a === b); // false — wrapper objects are not strictly equal
- Ce code montre la différence de type entre une primitive et un objet enveloppe, et comment ils se comportent lors d'une comparaison stricte. Dans la plupart des cas, évitez d'utiliser
new String()et privilégiez les primitives.
Méthodes de création de chaînes de caractères (littéraux et gabarits de chaîne)
Les gabarits de chaîne (template literals) sont utiles pour intégrer des variables et écrire des chaînes sur plusieurs lignes. Vous pouvez insérer des variables et évaluer des expressions de manière intuitive.
1const name = "Alice";
2const age = 30;
3
4// Template literal
5const greeting = `Name: ${name}, Age: ${age + 1}`;
6
7console.log(greeting); // "Name: Alice, Age: 31"
- Les gabarits de chaîne sont très lisibles et idéaux pour construire des chaînes complexes, y compris sur plusieurs lignes.
Méthodes courantes (recherche et extraction de sous-chaînes)
L'objet String possède de nombreuses méthodes de base.
1const text = "Hello, world! Hello again.";
2
3// search
4console.log(text.indexOf("Hello")); // 0
5console.log(text.indexOf("Hello", 1)); // 13
6console.log(text.includes("world")); // true
7console.log(text.startsWith("Hello")); // true
8console.log(text.endsWith("again.")); // true
9
10// slice / substring
11console.log(text.slice(7, 12)); // "world"
12console.log(text.substring(7, 12)); // "world"
sliceetsubstringsont similaires, mais gèrent différemment les indices négatifs.sliceinterprète les valeurs négatives comme des positions à partir de la fin. Soyez attentif à celui que vous utilisez.
Division et assemblage (split / join)
Il est courant de diviser une chaîne en tableau pour traitement, puis de la réassembler.
1const csv = "red,green,blue";
2const arr = csv.split(","); // ["red","green","blue"]
3
4console.log(arr);
5console.log(arr.join(" | ")); // "red | green | blue"
- Un schéma courant consiste à utiliser
splitpour diviser une chaîne, traiter le tableau résultant avecmapoufilter, puis utiliserjoinpour recombiner le tout.
Remplacement et expressions régulières
replace ne remplace que la première correspondance. Si vous voulez remplacer toutes les occurrences, utilisez l’indicateur g avec une expression régulière. En passant une fonction comme deuxième argument, vous pouvez également effectuer des remplacements dynamiques.
1const s = "foo 1 foo 2";
2
3// replace first only
4console.log(s.replace("foo", "bar")); // "bar 1 foo 2"
5
6// replace all using regex
7console.log(s.replace(/foo/g, "bar")); // "bar 1 bar 2"
8
9// replace with function
10const r = s.replace(/\d+/g, (match) => String(Number(match) * 10));
11console.log(r); // "foo 10 foo 20"
- Avec le remplacement dynamique par fonction, vous pouvez écrire de manière concise du code qui analyse et transforme les correspondances.
Changement de casse et normalisation
Pour la prise en charge et la comparaison multilingues, en plus de toLowerCase et toUpperCase, la normalisation Unicode (normalize) est également importante. Ceci est particulièrement nécessaire lors de la comparaison de caractères accentués.
1// Case conversion example:
2// "\u00DF" represents the German letter "ß".
3// In some locales, converting "ß" to uppercase becomes "SS".
4// JavaScript follows this behavior.
5console.log("\u00DF");
6console.log("\u00DF".toUpperCase()); // "SS"
7
8// Unicode normalization example:
9// "e\u0301" is "e" + a combining acute accent.
10// "\u00e9" is the precomposed character "é".
11// These two look the same but are different code point sequences.
12const a = "e\u0301";
13const b = "\u00e9";
14
15console.log(a === b); // false: different underlying code points
16console.log(a.normalize() === b.normalize()); // true: normalized to the same form
- Différentes représentations Unicode, comme les ligatures et les caractères combinés, ne seront pas égales telles quelles, donc utilisez
normalize()avant la comparaison.
Unicode et points de code (gestion des paires de substitution)
Les chaînes JavaScript sont des séquences d’unités de code UTF-16, donc certains caractères comme les émojis peuvent occuper deux unités de code pour un seul caractère. Pour manipuler les vraies unités de caractères, utilisez Array.from, l’opérateur de décomposition (...), ou for...of.
1// Emoji composed with multiple code points:
2// "\u{1F469}" = woman, "\u{200D}" = Zero Width Joiner (ZWJ),
3// "\u{1F4BB}" = laptop. Combined, they form a single emoji: 👩💻
4const s = "\u{1F469}\u{200D}\u{1F4BB}";
5console.log(s);
6
7// Length in UTF-16 code units (not actual Unicode characters):
8// Because this emoji uses surrogate pairs + ZWJ, the length may be > 1.
9console.log("Length:", s.length);
10
11// Iterate by Unicode code points (ES6 for...of iterates code points):
12// Each iteration gives a full Unicode character, not UTF-16 units.
13for (const ch of s) {
14 console.log(ch);
15}
16
17// Convert to an array of Unicode characters:
18console.log(Array.from(s));lengthretourne le nombre d’unités de code, vous n’obtiendrez donc pas forcément le compte attendu avec les émojis ou les ligatures.for...ofetArray.fromgèrent quelque chose de proche des caractères affichés (groupes de graphèmes), mais pour une prise en charge complète, utilisez une bibliothèque spécialisée.
Remplacement sécurisé dans les expressions régulières (traitement des saisies utilisateur)
Si vous oubliez d’échapper les entrées utilisateur lors de leur insertion dans une expression régulière, cela peut entraîner des comportements inattendus et des vulnérabilités. Échappez toujours la saisie utilisateur avant de l’utiliser dans un motif d’expression régulière.
1function escapeRegex(s) {
2 return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3}
4
5const userInput = "a+b";
6const pattern = new RegExp(escapeRegex(userInput), "g");
7console.log("a+b a+b".replace(pattern, "X")); // "X X"
- N’utilisez jamais directement une chaîne provenant d’un utilisateur dans une expression régulière : échappez-la toujours avant de créer la regex.
Conseils de performance : concaténation et gabarits
Lors de la concaténation de nombreuses petites chaînes à la suite, les mettre dans un tableau puis utiliser join peut être plus efficace. D’un autre côté, les chaînes gabarit sont très lisibles et suffisamment rapides dans la plupart des cas.
1// concatenation in loop (less ideal)
2let s = "";
3for (let i = 0; i < 1000; i++) {
4 s += i + ",";
5}
6
7// using array + join (often faster for many pieces)
8const parts = [];
9for (let i = 0; i < 1000; i++) {
10 parts.push(i + ",");
11}
12const s2 = parts.join("");- Les moteurs JavaScript modernes sont très optimisés, donc il n’est pas nécessaire de s’inquiéter des performances pour un petit nombre de concaténations. Cependant, si vous devez concaténer des dizaines de milliers de fois, utiliser
joinpeut être plus efficace.
Techniques pratiques : remplissage (padding), troncature et répétition
trim, padStart, padEnd et repeat sont des méthodes pratiques qui sont particulièrement utiles dans le traitement quotidien des chaînes de caractères. Elles sont souvent utilisées dans des situations pratiques comme le formatage des valeurs saisies ou la standardisation des formats de sortie.
1console.log(" hello ".trim()); // "hello"
2console.log("5".padStart(3, "0")); // "005"
3console.log("x".repeat(5)); // "xxxxx"
- Ces méthodes peuvent être utilisées pour normaliser la saisie de formulaires ou générer une sortie de largeur fixe.
Comparaison de chaînes (comparaison locale)
localeCompare est efficace pour comparer les chaînes selon l'ordre du dictionnaire de différentes langues. Vous pouvez spécifier la langue et des options de sensibilité (comme la casse).
1console.log(
2 "\u00E4".localeCompare("z", "de")
3); // may be -1 or other depending on locale
4
5console.log(
6 "a".localeCompare("A", undefined, { sensitivity: "base" })
7); // 0
- Pour des comparaisons internationalisées, utilisez
localeCompareet spécifiez la langue et les options appropriées.
Exemple pratique : conversion d’une ligne CSV en objet (workflow pratique)
Un cas d’usage courant est d’analyser une ligne CSV en objet en combinant split, trim et map. Pour les champs entre guillemets ou les fichiers CSV complexes, utilisez un analyseur CSV dédié.
1// simple CSV parse (no quotes handling)
2function parseCsvLine(line, headers) {
3 const values = line.split(",").map(v => v.trim());
4 const obj = {};
5 headers.forEach((h, i) => obj[h] = values[i] ?? null);
6 return obj;
7}
8
9const headers = ["name", "age", "city"];
10const line = " Alice , 30 , New York ";
11console.log(parseCsvLine(line, headers));
12// { name: "Alice", age: "30", city: "New York" }
- Cette méthode fonctionne pour les CSV simples mais ne gère pas le cas des virgules à l’intérieur d’un champ entre guillemets.
Pièges courants
Il existe certaines spécificités et comportements faciles à négliger dans la gestion des chaînes en JavaScript. Pour éviter des bogues inattendus, il est important de garder les points suivants à l’esprit.
- Utiliser
new String()peut mener à des résultats incorrects lors de la vérification ou la comparaison de types. Dans la plupart des cas, les chaînes primitives suffisent. - En Unicode, un seul caractère visible peut être composé de plusieurs unités de code. Ainsi, la valeur retournée par
lengthpeut ne pas correspondre au nombre réel de caractères affichés. - Lorsque vous insérez une saisie utilisateur dans une expression régulière, échappez-la toujours au préalable.
String.prototype.replace()ne remplace que la première occurrence par défaut. Si vous souhaitez remplacer toutes les occurrences, utilisez le drapeau/gdans votre expression régulière.- Les chaînes sont immuables, donc les opérations retournent toujours une nouvelle chaîne. Il est important d’assigner systématiquement la valeur retournée.
Résumé
Même si les chaînes JavaScript semblent simples, il est important de comprendre leurs particularités concernant Unicode et l’immutabilité. En maîtrisant les bases, vous pouvez grandement améliorer la fiabilité et la lisibilité de vos traitements de chaînes.
Vous pouvez suivre l'article ci-dessus avec Visual Studio Code sur notre chaîne YouTube. Veuillez également consulter la chaîne YouTube.