charCodeAt與codePointAt的用法:
相同點:
charCodeAt與codePointAt都是字符串實例上的方法,用途都是用來返回指定索引位字符的Unicode編碼。
不同點:
charCodeAt與codePointAt匹配索引位的規則不一樣。charCodeAt是根據碼元來匹配,codePointAt是根據碼點來進行匹配的。
先舉個例子:
可以發現一個非常神奇的事情。
有些中文字符𠮷 的長度不為1,並且charCodeAt與codePointAt對相同字進行處理返回的結果卻是不同的。
有人說念‘gei給’,有人說念'ji'同吉,反正是個古文字
這其中的原因就是charCodeAt是以一個碼元為一個索引,codePointAt是以一個碼點為一個索引進行處理的
Unicode使用16位二進制來存儲文字。我們將一個16位的二進制編碼叫做一個碼元(Code Unit),Unicode編碼范圍在0 - 2^16。也就是我們所說的占一個字節。
由於技術的發展,Unicode對文字編碼進行了擴展,將某些文字擴展到了32位(占用兩個碼元),並且,將某個文字對應的二進制數字叫做碼點(Code Point),Unicode編碼范圍在0 - 2^32,占2個字節。
特別要注意,碼點可以是一個碼元,也可以是兩個碼元。
字符串的length屬性返回的是碼元。所以在對一些字符串如果要處理長度的時候要注意這一點。
𠮷這個字的Unicode編碼是\ud842\udfb7,占用了兩個碼元。
所以當用charCodeAt(0)是匹配0位的碼元,也就是返回給我們55362。
當用codePointAt(0)是匹配0位的碼元,codePointAt能識別出字符串的碼點,所以反回134071。
𠮷.codePointAt(1)為什么返回的是57271呢?
這是因為索引位是根據碼元,而匹配的規則是根據碼點的規則。如果后面兩位碼元是一個碼點,就會當作一個碼點來處理。
總結
charCodeAt是以碼元為單位來處理的,也就是說按照每16位2進制數為單位。一個16位2進制數就是一位,所以處理不了Unicode擴展編碼字符(32位2進制)。他會把32位2進制數當成兩個16位2進制數處理
codePointAt也是以碼元位單位來處理的。與charCodeAt不同的地方是,當處理到當前位碼元時,如果超過了16位2進制數值的上線,他就明白這是一個32位2進制數,就會以32位2進制數當作一個來處理。
可以通過codePointAt來判斷當前字符是是32位的碼點還是16位的碼元
function is32bit(char, i) { //如果碼點大於了16位二進制的最大值,則其是32位的 return char.codePointAt(i) > 0xffff; }
同樣的,也可以通過這個方法來判斷以字符串真實的長度(碼點的長度)
function getLengthOfCodePoint(str) { var len = 0; for (let i = 0; i < str.length; i++) { //i在索引碼元 if (is32bit(str, i)) { //當前字符串,在i這個位置,占用了兩個碼元 i++; } len++; } return len; }