JS: String Index and Code Unit
What is javascript string
JavaScript string is sequence of code units that represent Unicode characters.
(Each “code unit” may be “half of a character” or full character.)
How is string indexed
JavaScript string is indexed by code units. The first code unit has index 0, etc.
If the string contains a character whose Code Point (Char ID) is ≥ 2^16 (e.g. 🦋 (U+1F98B: BUTTERFLY)) , that character is represented by two code units, thus occupies 2 indexes. Result of string functions may be unexpected.
What is code unit?
A Code Unit, is 2 bytes unit of a Unicode character in Unicode UTF-16 Encoding .
- In UTF-16 encoding, each Unicode character may have 2 or 4 bytes.
- If a character's Char ID (code point) is 16 bits value, its UTF-16 encoding is 2 bytes. Else, it is 4 bytes.
Code unit explained
- JavaScript string and character are based on Unicode standard, version 5.1 or later.
- In unicode, each character has an integer ID, called Code Point.
- Unicode specifies several encoding standards, most popular ones are UTF-8 and UTF-16.
- Encoding means, a standard that translate a character into sequence of Bytes. [see Unicode: Character Set, Encoding, UTF-8, Code Point]
- In UTF-16 encoding, each character is 2 or 4 bytes, depending on the character. (each 2 bytes is considered a unit, called code unit.)
- For characters whose codepoint is less than 2^16, the encoding of that char in UTF-16 is 2 bytes. Otherwise, it's 4 bytes.
- JavaScript defines element of string as sequence of 2-byte values of the characters encoded in UTF-16. That is, first encode the character in the string to bits by UTF-16, you get 2 or 4 bytes. Then, group every 2 bytes as a code unit. Then, index 0 is first 2-bytes unit, index 1 is second 2-bytes unit, etc. This means, when a string contain character whose codepoint is ≥ 2^16, the result of any string method, may be unexpected, because the index does not correspond to character.
Example: difference of character and code unit
console.assert("🦋".length === 2);
Here is a example with String.prototype.slice method with unexpected result.
// we want to take the substring abc console.log("🦋abc".slice(1)); // �abc // result is not what we want
What characters create problems?
Characters outside of Unicode Basic Multilingual Plane. Typically emoji.
How to go thru character (not code unit)
If you have a string that contains characters outside of Unicode Basic Multilingual Plane , the result of any string method may be unexpected.
Solution is to use for-of Loop or Array.from to go thru string.