#翻譯# 深刻JavaScript的Unicode難題(上)

退一步說, JavaScript處理Unicode時有些怪異. 這篇文章會說明JS在Unicode上使人痛苦的部分, 而後提供解決方案, 並說明在將來的ECMAScript6中是如何改善這些問題的.
 
Unicode基礎知識
爲了您能更好的理解Unicode在JavaScript裏的問題, 先確保你們瞭解Unicode爲什麼物.
最簡單的咱們能夠把 Unicode 想像成一個數據庫, 任何您能想到的符號都對應着一個數字(咱們把這個數字叫作它的碼位)和一個惟一的名字. 這樣一來, 咱們能夠方便的引用一個符號, 而沒必要直接使用這個符號自己.
例如:
A U+0041 LATIN CAPITAL LETTER A
a U+0061 LATIN SMALL LETTER A
© U+00A9 COPYRIGHT SIGN
U+2603 SNOWMAN
U+1F4A9 PILE OF POO
 
碼位一般用16進制數字表示, 用0補位, 至少4位數加上 U+ 前綴.
碼們的範圍是從U+0000至U+10FFFF. 能夠表示110萬個以上的符號.爲了良好的組織如此龐大的數據, Unicode把這些碼們分紅了17個平面, 大約每一個平面包含了6.5萬個碼位.
第一部分也是最重要的部分叫作基本多文種平面或BMP, 這部分包含了咱們一般會用到的符號. 在英文文本文檔中一般來講您只須要使用BMP就足夠了.
BMP以外還剩下100萬個可用碼位..包含這100萬個碼位的平面叫作補充平面星際平面.
星際平面十分容易辨識: 當您須要使用大於4位的16進制數來表示碼位時, 這個碼位就是星際碼位.
如今咱們已經瞭解了Unicode基礎知道, 下面來看看它是如何應用到JavaScript的字符串裏的.
 
轉義序列
您以前可能見過下面這些東西:
>> '\x41\x42\x43'
'ABC'
>> '\x61\x62\x63'
'abc'

 

這些叫作16進制轉義序列. 它們包含2位16進制數字表示碼位. 好比, '\x41' 表示 U+0041 LATIN CAPITAL LETTER A. 細心的讀者可能發現了, 這些轉義序列能夠表示U+0000至U+00FF的碼位.
 
還有一種常見的轉義:
>> '\u0041\u0042\u0043'
'ABC'
>> 'I \u2661 JavaScript!'
'I ♡ JavaScript!'

 

這些叫作Unicode轉義序列. 它們使用4位16進制數表示一個碼位. 好比: '\u2661' 表示 U+2661 WHITE HEART SUIT. 這些轉義序列表示的範圍是U+0000至U+FFFF, 包含了所有的BMP.
 
那麼對於其它平面呢? 好比星際平面? 咱們須要4位以上的16進制數才能表示它們的碼位... 如何來轉義??
 
在 ECMAScript 6 裏, 這個很簡單, 由於添加了一種新的轉義方式: Unicode碼位轉義.
例如:
>> '\u{41}\u{42}\u{43}'
'ABC'

>> '\u{1F4A9}'
'' // U+1F4A9 PILE OF POO

 

(好吧.. 個人編輯器已經顯示不了 PILE OF POO 了 - -!). 在大括號以前你可使用最多6位16進制數, 能夠表示出全部的Unicode碼位.
爲了向後兼容ECMAScript5和更早的環境, 一個很差的方案就是使用替代組合:
>> '\uD83D\uDCA9'

'' // U+1F4A9 PILE OF POO

 

由二者組成一個星際符號. 要注意的是這兩個組成部分已經失去了它們自己的碼位意義.
使用這種替代組合後, 全部的星際碼位均可以被表示了.. 你們應該已經感受到了, 單個碼位能夠表示的BMP與須要替代組合才能表示的星際符號混在一塊兒, 使人困惑, 甚至會形成討厭的後果.
在JavaScript裏計算字符數
若是你想計算字符串的長度你會怎麼作?
我首先想到的是用 length 屬性.
>> 'A'.length // U+0041 LATIN CAPITAL LETTER A
1

>> 'A' == '\u0041'
true

>> 'B'.length // U+0042 LATIN CAPITAL LETTER B
1

>> 'B' == '\u0042'
true

 

上面的例子裏, length 屬性確實表示了字符的數量. (這說得通, 由於若是咱們使用轉義序列來表示這個字符, 只須要一個轉義就能夠(\u0041 表示 A)).
來看一個不同的例子:
 
  
>> '퐀'.length // U+1D400 MATHEMATICAL BOLD CAPITAL A
2
>> '퐀' == '\uD835\uDC00'
true
>> '퐁'.length // U+1D401 MATHEMATICAL BOLD CAPITAL B
2
>> '퐁' == '\uD835\uDC01'
true
>> ''.length // U+1F4A9 PILE OF POO
2
>> '' == '\uD83D\uDCA9'
true
 
  
在JavaScript內部, 使用上文提到的替代組合來表示星際字符, 而且暴露出組成替代組合的2個字符. 若是你使用ECMAScript 5兼容的轉義序列來表示符號, 就須要2個轉義字符來表示一個星際符號. 這使人困惑, 由於人們一般是以一個Unicode符號或字母的一個總體來考慮它們, 而不是把一個星際字符想成2部分.
(未完待續)
相關文章
相關標籤/搜索