codePointAt()與charCodeAt()方法區(qū)別

charCodeAt與codePointAt的用法:

  • 相同點(diǎn):
      charCodeAt與codePointAt都是字符串實(shí)例上的方法,用途都是用來(lái)返回指定索引位字符的Unicode編碼。
  • 不同點(diǎn):
       charCodeAt與codePointAt匹配索引位的規(guī)則不一樣。charCodeAt是根據(jù)碼元來(lái)匹配,codePointAt是根據(jù)碼點(diǎn)來(lái)進(jìn)行匹配的。

JavaScript 內(nèi)部,字符以 UTF-16(字符用兩個(gè)字節(jié)或四個(gè)字節(jié)表示) 的格式儲(chǔ)存,碼點(diǎn)范圍介于U+0000到U+FFFF,每個(gè)字符固定為2個(gè)字節(jié),一個(gè)碼元。對(duì)于那些需要4個(gè)字節(jié)儲(chǔ)存的字符(Unicode 碼點(diǎn)大于0xFFFF的字符),兩個(gè)碼元,JavaScript 會(huì)認(rèn)為它們是兩個(gè)字符。

在計(jì)算機(jī)發(fā)展的早期,由于存儲(chǔ)空間寶貴,Unicode使用16位二進(jìn)制來(lái)存儲(chǔ)文字。也就是一個(gè)碼元來(lái)存儲(chǔ)一個(gè)文字。
由于技術(shù)的發(fā)展,Unicode對(duì)文字編碼進(jìn)行了擴(kuò)展,將某些文字?jǐn)U展到了32位(占用兩個(gè)碼元),而一個(gè)文字對(duì)應(yīng)的二進(jìn)制數(shù)字是一個(gè)碼點(diǎn),所以使用32位二進(jìn)制數(shù)字存儲(chǔ)的文字(一個(gè)碼點(diǎn)=兩個(gè)碼元)
特別要注意,碼點(diǎn)可以是一個(gè)碼元,也可以是兩個(gè)碼元。

字符串的length屬性返回的是碼元。所以在對(duì)一些字符串如果要處理長(zhǎng)度的時(shí)候要注意這一點(diǎn)。

let str="A";              
let strSpecial = "??"; 
console.log(str.length);               // 1
console.log(strSpecial.length);       // 2

(1)length屬性返回對(duì)應(yīng)幾個(gè)碼元字符
(2)str的Unicode是\u0041\只有一個(gè)字符,strSpecial Unicode編碼是\ud842\udfb7,雙字節(jié)兩個(gè)碼元,js識(shí)別為2個(gè)字符

let str="A";
let strSpecial = "??"; 
console.log(str.charCodeAt(0));               // 65
console.log(str.codePointAt(0));              // 65
console.log(strSpecial.charCodeAt(0));        // 55362
console.log(strSpecial.codePointAt(0));       // 134071

ES6 提供了codePointAt(0)方法,能夠正確處理 4 個(gè)字節(jié)儲(chǔ)存的字符,根據(jù)字符串碼元的位置得到其碼點(diǎn)。

  • ??這個(gè)字的Unicode編碼是\ud842\udfb7,占用了兩個(gè)碼元。
  • 所以當(dāng)用charCodeAt(0)是匹配0位的碼元,前兩個(gè)字節(jié)值 55362,toString(16)是ud842。
  • 當(dāng)用codePointAt(0)是匹配0位的碼點(diǎn),codePointAt能識(shí)別出字符串的碼點(diǎn),所以反回134071。

codePointAt方法返回的是碼點(diǎn)的十進(jìn)制值,如果想要十六進(jìn)制的值,可以使用toString方法轉(zhuǎn)換一下。

let a = 'A';
 let s = '??';
 a.codePointAt(0).toString(16) 
"41"
 s.codePointAt(0).toString(16) 
"20bb7"

但是這里需要注意參數(shù):

let strSpecial = "??"; 
console.log(strSpecial.charCodeAt(1));           
console.log(strSpecial.codePointAt(0));    
console.log(strSpecial.codePointAt(1));
image.png

codePointAt(1)與charCodeAt(1)的返回值相同,都是返回后兩個(gè)字節(jié)的碼元值。
這是因?yàn)樗饕皇歉鶕?jù)碼元,而匹配的規(guī)則是根據(jù)碼點(diǎn)的規(guī)則。如果后面兩位碼元是一個(gè)碼點(diǎn),就會(huì)當(dāng)作一個(gè)碼點(diǎn)來(lái)處理。

let str="A";
let strSpecial = "??A"; 
console.log(str.charCodeAt(0));
console.log(strSpecial.codePointAt(0));
console.log(strSpecial.codePointAt(1));
console.log(strSpecial.codePointAt(2));
image.png

strSpecial.codePointAt(1)取的不是A的字符值,是strSpecial后兩個(gè)字節(jié)的碼元值,而.codePointAt(2)才取得A的字符值,與str.charCodeAt(0)一樣。

解決順序問(wèn)題的配套辦法是使用for...of循環(huán),因?yàn)樗梢宰R(shí)別UTF-32(字符用四個(gè)字節(jié)表示,兩個(gè)碼元)

let strSpecial = "??"; 
for (let char of strSpecial) {
  console.log(char.codePointAt(0));
}

關(guān)于for of可以參閱JavaScript for of 循環(huán)一章節(jié)。
codePointAt()方法是測(cè)試一個(gè)字符由兩個(gè)字節(jié)還是由四個(gè)字節(jié)組成的最簡(jiǎn)單方法。

function is32Bit(c) {
  // 如果碼點(diǎn)大于了16位二進(jìn)制的最大值,則其是32位的
  return c.codePointAt(0) > 0xFFFF;
}
is32Bit("??") // true
is32Bit("a") // false

有用的字符編碼筆記:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

歡迎大佬指點(diǎn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 字符的 Unicode 表示法 codePointAt() String.fromCodePoint() 字符串的...
    卞卞村長(zhǎng)L閱讀 831評(píng)論 0 0
  • ES6學(xué)習(xí)筆記-字符串與正則表達(dá)式 JS字符串編碼 在ES6之前,JS的字符串以16位字符編碼(UCS-2)為基礎(chǔ)...
    小線亮亮閱讀 696評(píng)論 0 0
  • 之前突然發(fā)現(xiàn)自己對(duì)字符編碼還是一知半解,基本上只是聽(tīng)說(shuō)過(guò)各種編碼的名字,對(duì)它們之間的特點(diǎn)和區(qū)別還是不甚了解。所以這...
    L_Zephyr閱讀 2,183評(píng)論 0 4
  • 白露已過(guò),秋分已到來(lái)。 又到一年中秋節(jié), 卻怎么也快樂(lè)不起來(lái); 數(shù)一數(shù)你已遠(yuǎn)去415日, 你在那邊還好嗎? 天涼了...
    淡淡的云_f0fd閱讀 1,422評(píng)論 16 6
  • """------ author == 李 墨 ------""" 1 聲明一個(gè)字典保存一個(gè)學(xué)生的信息,學(xué)生...
    snow_5ca2閱讀 239評(píng)論 0 0

友情鏈接更多精彩內(nèi)容