關于 JavaScript 字符串的一個小知識
說起字符串,我們再熟悉不過了。接觸編程的第一個經典任務就是輸出字符串:Hello, world。但是你知道 JavaScript 字符串在計算機里是怎么表示的嗎?
最簡單直觀但不太準確的的理解就是,字符串就是由英文字母、數字和標點符號等這些字符組成的序列。比如下面這個字符串就是由5個字母和一個感嘆號組成的:
- const message = 'Hello!';
同時也可以看出該字符串的字符數是6:
- const message = 'Hello!';
- message.length; // => 6
如果字符串是由這些可見字符(也就是 127 個 ASCII 字符) 組成的,這樣理解沒有問題。但是,一旦碰到不常見的符號,比如一些表情字符😀, 😁, 😈,可能會得到意外的結果:
- const smile = '😀';
- smile.length; // => 2
是不是很奇怪?明明只有一個字符,長度怎么會是 2 呢?這是因為,JavaScript 字符串實際上是由編碼單元構成的,而不是可見字符序列。
ECMA 262 規范里是這么描述 JavaScript 字符串的:
String 類型是由零或多個 16 位無符號整數值組成的有序序列的集合。字符串類型通常用于表示運行中的 ECMAScript 程序中的文本數據,在這種情況下,字符串中的每個元素都被視為 UTF-16 編碼單元值。
簡單說,JavaScript 字符串就是 UTF-16 編碼單元序列,一串數字而已。
一個編碼單元就是位于 0x0000 和 0xFFFF 之間的一個數字,編碼單元與字符之間有個對應關系。例如,編碼單元 0x0048 對應了實際的字符 H:
- const letter = '\u0048';
- letter === 'H' // => true
如果把一整個字符串'Hello!'用編碼單元表示就是這樣:
- const message = '\u0048\u0065\u006C\u006C\u006F\u0021';
- message === 'Hello!'; // => true
- message.length; // => 6
可以看到,這個字符串有6個編碼單元,每個編碼單元對應一個字符?;径辔姆N平面 BMP(Basic Multilingual Plane)中的任意一個字符,都可以用一個 UTF-16 編碼單元表示。但是,在這個范圍以外的字符,就需要 2 個 UTF-16 編碼單元來表示了。比如前面提到的笑臉符號,編碼是\uD83D\uDE00:
- const smile = '\uD83D\uDE00';
- smile === '😀'; // => true
- smile.length; // => 2
這兩個編碼單元是成對存在的,用于表示超出 0xFFFF 的字符。不能拆開,否則就變成無法識別的亂碼了。另外,這里的.length是2,說明這個屬性其實是字符串編碼單元的個數,而不是字符數。在需要判斷字符數量的時候就要注意了,根據.length得到的結果是不準確的。那要怎么解決呢?可以用這種辦法:
- const message = 'Hello!';
- const smile = '😀';
- [...message].length; // => 6
- [...smile].length; // => 1
如果覺得這個關于 JavaScript 字符串的小知識對你有用,歡迎分享給你的小伙伴們!