Réponse technique directe
Les chaînes JavaScript sont des séquences d'unités de code UTF-16 de 16 bits, et non des caractères Unicode individuels ou des symboles perçus par l'utilisateur. Les caractères supplémentaires hors du Basic Multilingual Plane (comme les emojis et les idéogrammes rares) nécessitent deux unités de code UTF-16 (une paire de substitution), tandis que les graphèmes composés nécessitent plusieurs points de code.
La différence entre unités de code UTF-16, points de code Unicode et clusters de graphèmes en JavaScript
const emoji = '😀';
// 1. String.prototype.length counts UTF-16 code units
console.log(emoji.length); // 2
// 2. String iterator ([...str]) counts Unicode code points
console.log([...emoji].length); // 1
// 3. Composite emoji with Zero-Width Joiner (ZWJ)
const family = '👨👦';
console.log(family.length); // 5 code units
console.log([...family].length); // 3 code points
// 4. Intl.Segmenter counts user-perceived grapheme clusters
const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
console.log([...segmenter.segment(family)].length); // 1 user character
2
1
5
3
1
Pourquoi cela arrive : le modèle de chaîne d'ECMAScript
Pour comprendre le comportement des chaînes JavaScript, les développeurs doivent maîtriser les trois couches distinctes de représentation Unicode dans le navigateur et dans Node.js.
1. L'héritage historique d'UTF-16
2. Unités de code vs points de code
3. Points de code vs clusters de graphèmes perçus par l'utilisateur
4. Substituts isolés et chaînes mal formées
Modèle d'exécution du langage et du runtime
V8 utilise une optimisation de représentation interne : les chaînes ne contenant que des caractères Latin-1 (U+0000..U+00FF) sont stockées comme des tableaux de 1 octet (SeqOneByteString). Les chaînes contenant un caractère au-dessus d'U+00FF sont promues en tableaux UTF-16 de 2 octets (SeqTwoByteString).
Erreurs courantes vs modèles de production
Découvrez quels modèles échouent en production et leurs alternatives modernes conformes aux standards.
Compter les caractères visibles par l'utilisateur
Compteur de caractères dans les formulaires d'interface, limites SMS, champs de biographie.const str = '👨💻';
console.log(str.length);
// Returns 5 (UTF-16 code units)
const str = '👨💻';
const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
console.log([...segmenter.segment(str)].length);
// Returns 1 (true user-perceived character)
Itérer sur les caractères d'une chaîne
Analyse de jetons, construction de transformateurs de chaînes personnalisés.const text = '🔥hello';
for (let i = 0; i < text.length; i++) {
console.log(text[i]); // splits 🔥 into \uD83D and \uDD25!
}
const chars = text.split(''); // ['\uD83D', '\uDD25', 'h', 'e', 'l', 'l', 'o']
const text = '🔥hello';
for (const char of text) {
console.log(char); // '🔥', 'h', 'e', 'l', 'l', 'o'
}
const chars = [...text]; // ['🔥', 'h', 'e', 'l', 'l', 'o']
Lire des points de code numériques
Convertisseurs d'encodage de caractères, hachage cryptographique, métriques de polices.const char = '😀';
console.log(char.charCodeAt(0).toString(16));
// Returns 'd83d' (High surrogate only!)
const char = '😀';
console.log(char.codePointAt(0).toString(16));
// Returns '1f600' (True Unicode code point!)
Écrire des séquences d'échappement Unicode
Littéraux de code source, charges utiles JSON, définitions d'expressions régulières.const fire = '\uD83D\uDD25'; // 🔥
// Prone to transposition, hard to read, manual math needed
const fire = '\u{1F525}'; // 🔥
const smile = '\u{1F600}'; // 😀
Matrice des cas limites et invariants
Une matrice de tests diversifiée comparant le comportement des caractères entre ASCII, signes combinants, emojis, drapeaux et fragments de substitution.
| Cas de test | Glyphe d'entrée | Unités de code | Points de code | Graphèmes | Catégorie | Explication technique |
|---|---|---|---|---|---|---|
| Lettre latine ASCII | A |
1
|
1
|
1
|
Basic Latin | U+0041 tient dans un seul octet de 7 bits, une unité de code de 16 bits et un point de code. |
| Accent précomposé | é |
1
|
1
|
1
|
Latin-1 Supplement | U+00E9 accent aigu précomposé dans le BMP. 1 unité de code, 1 point de code, 1 graphème. |
| Accent décomposé | é |
2
|
2
|
1
|
Combining Mark | Lettre de base e (U+0065) + accent aigu combinant (U+0301). 2 points de code rendus comme 1 graphème visuel. |
| Symbole monétaire | € |
1
|
1
|
1
|
Currency | Signe euro U+20AC situé dans le BMP. 1 unité de code, 1 point de code, 1 graphème. |
| Emoji standard | 😀 |
2
|
1
|
1
|
Supplementary Plane | Visage souriant U+1F600 dans le plan 1. Encodé comme 2 unités de code UTF-16 (D83D DE00). |
| Séquence d'emoji avec ZWJ | 👨👦 |
5
|
3
|
1
|
Emoji Sequence | Homme (U+1F468) + ZWJ (U+200D) + garçon (U+1F466). 3 points de code joints en 1 glyphe de famille. |
| Drapeau arc-en-ciel | 🏳️🌈 |
6
|
4
|
1
|
Emoji Sequence | Drapeau blanc (U+1F3F3) + sélecteur de variante 16 (U+FE0F) + ZWJ (U+200D) + arc-en-ciel (U+1F308). |
| Drapeau national (indicateurs régionaux) | 🇺🇳 |
4
|
2
|
1
|
Flag Sequence | Indicateur régional U (U+1F1FA) + indicateur régional N (U+1F1F3). 2 points de code, 1 graphème. |
| Substitut élevé isolé |
1
|
1
|
1
|
Surrogate Fragment | Substitut élevé isolé 0xD83D. Valide en mémoire ECMAScript, mais mal formé en UTF-8. |
Core API Reference
Standard library methods, runtime signatures, and Unicode semantics.
str.codePointAt(index: number): number | undefined
Renvoie la valeur du point de code Unicode (entier) à l'index d'unité de code UTF-16 spécifié.
String.fromCodePoint(...codePoints: number[]): string
Crée une chaîne à partir d'une séquence de points de code Unicode de 21 bits.
new Intl.Segmenter(locales?: string | string[], options?: { granularity: "grapheme" | "word" | "sentence" })
Fournit une segmentation de texte sensible à la locale, permettant une itération fiable des clusters de graphèmes perçus par l'utilisateur.
str.normalize(form?: "NFC" | "NFD" | "NFKC" | "NFKD"): string
Renvoie la forme de normalisation Unicode de la chaîne appelante.
new RegExp(pattern, "v")
Indicateur d'expression régulière UnicodeSets d'ECMAScript 2024 activant les opérations d'ensembles et les propriétés de chaîne.
Inspecteur interactif de chaînes et d'Unicode en JavaScript
Testez n'importe quelle chaîne ou séquence d'emojis en temps réel pour inspecter ses unités de code UTF-16, ses points de code Unicode et ses clusters de graphèmes dans votre navigateur.
Décomposition du point de code :
Normes et provenance des sources
Tous les invariants techniques, API et comportements de ce guide sont vérifiés par rapport aux spécifications primaires officielles.
ECMAScript 2024 Language Specification (ECMA-262 15th Edition)
Clause : §6.1.4 The String Type & §22.1 String Objects
ECMAScript Internationalization API (ECMA-402)
Clause : §18 Intl.Segmenter Objects
Unicode Standard Annex #29: Unicode Text Segmentation
Clause : §3 Grapheme Cluster Boundaries
Unicode Standard Annex #15: Unicode Normalization Forms
Clause : §1 Normalization Forms
JavaScript String Reference & UTF-16 Representation
Clause : UTF-16 Characters, Unicode Code Points, and Grapheme Clusters