HomepageExploring JavaScript (ES2024 Edition)
You can support this book: buy it or donate
(Ad, please don’t block.)

21 Unicode – a brief introduction (advanced)

Unicode is a standard for representing and managing text in most of the world’s writing systems. Virtually all modern software that works with text, supports Unicode. The standard is maintained by the Unicode Consortium. A new version of the standard is published every year (with new emojis, etc.). Unicode version 1.0.0 was published in October 1991.

21.1 Code points vs. code units

Two concepts are crucial for understanding Unicode:

21.1.1 Code points

The first version of Unicode had 16-bit code points. Since then, the number of characters has grown considerably and the size of code points was extended to 21 bits. These 21 bits are partitioned in 17 planes, with 16 bits each:

Planes 1-16 are called supplementary planes or astral planes.

Let’s check the code points of a few characters:

> 'A'.codePointAt(0).toString(16)
> 'ü'.codePointAt(0).toString(16)
> 'π'.codePointAt(0).toString(16)
> '🙂'.codePointAt(0).toString(16)

The hexadecimal numbers of the code points tell us that the first three characters reside in plane 0 (within 16 bits), while the emoji resides in plane 1.

21.1.2 Encoding Unicode code points: UTF-32, UTF-16, UTF-8

The main ways of encoding code points are three Unicode Transformation Formats (UTFs): UTF-32, UTF-16, UTF-8. The number at the end of each format indicates the size (in bits) of its code units. UTF-32 (Unicode Transformation Format 32)

UTF-32 uses 32 bits to store code units, resulting in one code unit per code point. This format is the only one with fixed-length encoding; all others use a varying number of code units to encode a single code point. UTF-16 (Unicode Transformation Format 16)

UTF-16 uses 16-bit code units. It encodes code points as follows:

As a consequence, each UTF-16 code unit is either:

If a surrogate appears on its own, without its partner, it is called a lone surrogate.

This is how the bits of the code points are distributed among the surrogates:

0bhhhhhhhhhhllllllllll // code point - 0x10000
0b110110hhhhhhhhhh     // 0xD800 + 0bhhhhhhhhhh
0b110111llllllllll     // 0xDC00 + 0bllllllllll

As an example, consider code point 0x1F642 (🙂) that is represented by two UTF-16 code units – 0xD83D and 0xDE42:

> '🙂'.codePointAt(0).toString(16)
> '🙂'.length
> '🙂'.split('')
[ '\uD83D', '\uDE42' ]

Let’s derive the code units from the code point:

> (0x1F642 - 0x10000).toString(2).padStart(20, '0')
> (0xD800 + 0b0000111101).toString(16)
> (0xDC00 + 0b1001000010).toString(16)

In contrast, code point 0x03C0 (π) is part of the BMP and therefore represented by a single UTF-16 code unit – 0x03C0:

> 'π'.length
1 UTF-8 (Unicode Transformation Format 8)

UTF-8 has 8-bit code units. It uses 1–4 code units to encode a code point:

Code pointsCode units
0000–007F0bbbbbbb (7 bits)
0080–07FF110bbbbb, 10bbbbbb (5+6 bits)
0800–FFFF1110bbbb, 10bbbbbb, 10bbbbbb (4+6+6 bits)
10000–1FFFFF11110bbb, 10bbbbbb, 10bbbbbb, 10bbbbbb (3+6+6+6 bits)


Three examples:

CharacterCode pointCode units
π0x03C011001111, 10000000
🙂0x1F64211110000, 10011111, 10011001, 10000010

21.2 Encodings used in web development: UTF-16 and UTF-8

The Unicode encoding formats that are used in web development are: UTF-16 and UTF-8.

21.2.1 Source code internally: UTF-16

The ECMAScript specification internally represents source code as UTF-16.

21.2.2 Strings: UTF-16

The characters in JavaScript strings are based on UTF-16 code units:

> const smiley = '🙂';
> smiley.length
> smiley === '\uD83D\uDE42' // code units

For more information on Unicode and strings, consult “Atoms of text: code points, JavaScript characters, grapheme clusters” (§22.7).

21.2.3 Source code in files: UTF-8

HTML and JavaScript are almost always encoded as UTF-8 these days.

For example, this is how HTML files usually start now:

<!doctype html>
  <meta charset="UTF-8">

For HTML modules loaded in web browsers, the standard encoding is also UTF-8.

21.3 Grapheme clusters – the real characters

The concept of a character becomes remarkably complex once we consider the various writing systems of the world. That’s why there are several different Unicode terms that all mean “character” in some way: code point, grapheme cluster, glyph, etc.

In Unicode, a code point is an atomic part of text.

However, a grapheme cluster corresponds most closely to a symbol displayed on screen or paper. It is defined as “a horizontally segmentable unit of text”. Therefore, official Unicode documents also call it a user-perceived character. One or more code points are needed to encode a grapheme cluster.

For example, the Devanagari kshi is encoded by 4 code points. We use Array.from() to split a string into an Array with code points (for details, consult “Working with code points” (§22.7.1)):

Splitting the grapheme cluster for the Devanagari _kshi_ into code points.

Flag emojis are also grapheme clusters and composed of two code points – for example, the flag of Japan:

Splitting a flag emoji into code points.

21.3.1 Grapheme clusters vs. glyphs

A symbol is an abstract concept and part of written language:

The distinction between a concept and its representation is subtle and can blur when talking about Unicode.

Icon “external”More information on grapheme clusters

For more information, consult “Let’s Stop Ascribing Meaning to Code Points” by Manish Goregaokar.