charCodeAt與codePointAt的用法:
相同點:
- charCodeAt與codePointAt都是字串例項上的方法,用途都是用來返回指定索引位字元的Unicode編碼。
不同點:
- charCodeAt與codePointAt匹配索引位的規則不一樣。charCodeAt是根據碼元來匹配,codePointAt是根據碼點來進行匹配的。
先舉個例子:
可以發現一個非常神奇的事情。
有些中文字元 𠮷 、 𪚥
的長度不為1,並且charCodeAt
與codePointAt
對相同字進行處理返回的結果卻是不同的。
這其中的原因就是charCodeAt
是以一個碼元為一個索引,codePointAt
是以一個碼點為一個索引進行處理的
Unicode使用16位二進位制來儲存文字。我們將一個16位的二進位制編碼叫做一個碼元(Code Unit),Unicode編碼範圍在0 - 2^16。也就是我們所說的佔2個位元組。
由於技術的發展,Unicode對文字編碼進行了擴充套件,將某些文字擴充套件到了32位(佔用兩個碼元),並且,將某個文字對應的二進位制數字叫做碼點(Code Point),Unicode編碼範圍在0 - 2^32,佔4個位元組。
特別要注意,碼點可以是一個碼元,也可以是兩個碼元。
字串的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;
}