JS 中常用的編碼(Encode)與解碼(Decode)
前情提要:
本篇筆記起初主要想記錄的內容是 JS 中常用編碼與解碼應用場景,但在查閱資料的過程中發現, JS 中常見的編碼方法牽涉了許多編碼規範的專有名詞,如:ASCII、Unicode、UTF-8、Base64 等等。為了讓讀者能更容易理解 JavaScript 中的編碼原理,我決定先介紹這些基本的編碼知識,這樣在進入 JavaScript 的具體應用時,大家對這些專有名詞會有一定程度的認識,更能掌握其背後的邏輯。
ASCII
ASCII(美國資訊交換標準代碼)是一種早期的字符編碼系統,主要用於電腦和通訊設備間的文本資料交換。它最早於 1963 年制定,並成為國際標準。ASCII 使用 7 位二進制數來表示字符,總共可以表示 128 個字符,包含 33 個控制字符(如換行、退格)和 95 個可打印字符(如大寫和小寫字母、數字、標點符號等)。每個字符在 ASCII 表中對應一個從 0 到 127 的數字代碼。
例如:
- 字母 A 的 ASCII 碼是 65
- 字母 a 的 ASCII 碼是 97。
在 JavaScript 中,我們可以使用 String.charCodeAt() 方法獲取字符的 ASCII 碼,或者使用 String.fromCharCode() 從 ASCII 碼創建字符。例如:
// 獲取字符的 ASCII 碼
console.log('A'.charCodeAt(0)); // 輸出 65
// 將 ASCII 碼轉換回字符
console.log(String.fromCharCode(65)); // 輸出 A
ASCII 在早期電腦系統中廣泛使用,但由於只能表示 128 個字符,無法涵蓋世界其他語言,因此現在已逐漸被更通用的 Unicode 編碼所取代。
Unicode
Unicode 是什麼?
Unicode 是一個字符集,又被稱為萬國碼,旨在為全球所有的字符分配唯一的編號,稱為代碼點(code point)。每個代碼點以 U+xxxx 的16進制格式表示,例如,U+0041 表示拉丁字母 A。
Unicode 的範圍從 U+0000 到 U+10FFFF,涵蓋各種語言和符號。
Unicode 編碼的挑戰
雖然 Unicode 可以表示所有字符,但不同字符需要的存儲空間(即 bytes 數)不一樣,某些字符可能只需要 1 個 byte,而其他字符可能需要 2 到 4 個 bytes。這導致了一個問題:
電腦要如何 在連續的 bytes 中區分這些 bytes 長度不一的字符?
例如:漢字「心」的 Unicode 碼點是 U+5FC3,轉換為二進制是 101111110000011,二進制有15位,需要至少 2 個 bytes 來表示,而下個字符可能轉換為二進制後的位數會更多,需要用 3 個 bytes 來表示。那麼電腦怎麼知道前兩個 bytes 是用來表示一個字符,後三個 bytes 是用來表示另一個字符的呢?
你可能想得到,最簡單粗暴的解法就是直接取 Unicode 中需要最多 bytes 的字符為標準。假設 Unicode 中需要用到最多 bytes 的字符所需要的 bytes 數為 4 bytes,那麼讓所有字符一律用 4 bytes 來表示就可以統一規格了。但這麼做會造成極大的空間浪費。以英文字符來說,所有英文字的 Unicode 轉為二進位後都可以只用一個 byte 來表示,但如果每個字符都使用 4 bytes 表示,就必須用 4 倍的儲存空間,這種浪費是很難被接受的。
為了解決這個問題,字符編碼方式(如 UTF-8 和 UTF-16)應運而生,它們定義了一套規則,允許不同字符使用不同長度的字節表示,且能讓電腦正確辨識每個字符的邊界。
UTF-8 編碼
UTF-8 是什麼?
UTF-8 是目前最常見的可變長度的字符編碼方式,它使用 1 到 4 個 bytes 來表示字符。它的最大優勢在於與 ASCII 兼容:ASCII 編碼的字符在 UTF-8 中保持不變,這讓英文文本和一些控制字符能直接使用 UTF-8 編碼,而不需要額外的轉換。
UTF-8 的編碼規則
- 單字節字符:第一位設為 0,後面 7 位對應 ASCII 碼,這使得 UTF-8 可以與 ASCII 兼容。
- 多字節字符:首字節中的前幾位設為 1,表示該字符由多少字節組成,後續字節的前兩位為
10,剩下的位用來填充字符的 Unicode 代碼點。
| Unicode 範圍 | UTF-8 表示形式 |
|---|---|
U+0000 - U+007F | 0xxxxxxx |
U+0080 - U+07FF | 110xxxxx 10xxxxxx |
U+0800 - U+FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
U+10000 - U+10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
UTF-8 的解碼規則
- 如果字節的第一位是 0,則該字節單獨表示一個字符(即 ASCII 字符)。
- 如果字節的前幾位是 1,則表示該字符由多個字節組成,電腦可以根據字節的結構正確解碼。