在介紹字元串之前,有必要先了解一點Unicode的基礎知識,有助於理解ES6提供的新功能和新特性。
一、Unicode
Unicode是一種字符集(即多個字元的集合),它的目標是涵蓋世界上的所有字元,為其提供唯一的標識符,這個標識符叫做碼位或碼點(Code Point)。碼位既可以用一個從0開始計算的數值表示,也可以用U+作為前綴後面緊跟十六進位數表示。
Unicode只規定了每個字元的碼位,但並沒有規定如何用位元組序列(即二進位數字存儲方式)表示字元,於是就出現了字元編碼(Character Encoding)。Unicode包含多種字元編碼,例如UTF-8、UTF-16等,此處的UTF前綴是Unicode Transformation Format的縮寫,即統一轉換格式,它們都是Unicode的一種實現方式。其中UTF-8是變長編碼,使用1~4個位元組表示一個字元,它的最小編碼單元(Code Unit)為一個位元組(即8位);而UTF-16使用2或4個位元組表示一個字元,它的最小編碼單元為兩個位元組(即16位)。
Unicode的碼位範圍從U+0000到U+10FFFF,由於包含的字元眾多,因此會把它們劃分成17組,組也叫平面(Plane),每個平面包含2^16=65536個字元,其中第0個平面叫做基本多語言平面(Basic Multilingual Plane,簡稱BMP),碼位範圍從U+0000到U+FFFF(包含了ASCII碼),剩下的16個為輔助平面(Supplementary Plane)。
JavaScript採用了UTF-16編碼的Unicode字符集,BMP中的字元可用一個16位的編碼單元表示,而輔助平面中的字元則要遵循UTF-16的代理對(Surrogate Pair)規則,即用兩個編碼單元表示。這意味著JavaScript中的一個Unicode字元,它的長度有可能是1,但也有可能是2。由於JavaScript中的字元串方法(例如substring()、charAt()等)都會受到這種編碼規則的影響,因此有時候會返回出人意料的結果。不過好在ES6大幅增強了對Unicode的支持,有效避免了這種意外性情況的發生。
二、Unicode字元
在JavaScript中,Unicode字元可以用Unicode轉義字元的形式(即uXXXX)表示,其中4個「X」表示字元的碼位,而「X」是一個16進位字元,還要注意一點,ES5只支持4個「X」。也就是說,這種形式只能表示BMP中的字元(即U+0000到U+FFFF內的字元),如果要使用輔助平面中的字元,那麼需要寫兩個Unicode轉義字元。下面代碼中,第一個字元是BMP中的「向」,第二個字元是2號平面中的「??」。
let word1 = "u5411";
console.log(word1); //"向"
let word2 = "ud842udfb3";
console.log(word2); //"??"
ES6為Unicode字元提供了一種新形式,只需把碼位用花括弧包裹,就能支持輔助平面中的字元。下面使用了新形式來描述字元「??」。
let word3 = "u{20BB3}";
console.log(word3); //"??"
三、Unicode標準化
Unicode標準化(Unicode Normalization),也叫Unicode正規化或Unicode規範化,可將字元轉換成指定的位元組序列,統一表現形式,以及確定字元之間的等價性。例如字元「ü」,既可以只用U+00FC表示,也可以用U+0075(u)和U+0308(¨)組合表示,雖然對於人類來說,兩種表示法得到的結果在視覺上是完全相同的,但對於計算機來說卻是不同的,如下所示。
var mark1 = "u00FC",
mark2 = "u0075u0308";
mark1 === mark2; //false
ES6新增了一個原型方法normalize(),可以將字元串標準化,修改上面的例子,就能得到相等的結果,如下所示。
mark1.normalize() === mark2.normalize(); //true
normalize()方法可以接收一個字元串參數,但只有4個可選值(如表4所示),其中「NFC」是方法的默認值。