JavaScript 什么是 Base64 編碼,如何實現 Base64 ?


一、什么是 Base64 ?

一句話可以概括:base64 是一種用64個字符(1字節 = 8bit)來表示任意 8bit 位的二進制數據的方法。

它的作用非常廣泛,如迅雷下載的下載鏈接、前端的 dataURL、郵件傳輸等等。得益於用可見字符對二進制的直接轉化, 使得base64可以無視平台,無視語言,無視網頁編碼准確無誤的傳遞信息,非常便捷。

 

二、Base64 的原理

base64 編碼來自於 64 個可見字符。如表所示:

從上表可知 base64 一共只有2的6次方64個字符(6bit)。而實際上 1 bytes = 8bit,那么它是如何轉化的呢,下面我們直接用代碼進行說明。

1.將所有字符轉化為二進制形式:

var text = "abc"; var code = "";
for(let i of text){ // charCode
let number = i.charCodeAt().toString(2); // 將 toString 前面省略的0補上 for(let a = 0; a <= 8 - number.length;a++){ number = 0 + number; } code += number }

2.將二進制數據每 6bit 位替換成一個 base64 字符:

// code 按 6bit 一組 011000 010110 001001 100011 var base64Code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; let encode = ''; for(let i = 0;i<code.length;i += 6){ let number = code.slice(i,i+6); encode += base64Code[parseInt(number,2)]; } console.log(encode); // YWJj

 

這一步其實已經完成了對 base64 的編碼,我們成功的把 "abc" 轉化成了 "YWJj"。不要懷疑,就是這么容易。但是,假如字節總數不能被 6 整除呢? 我們知道 6 和 8 的最小公倍數是 24,也就是說,我們必須找到 3 bytes 的數據,並它替換成 4 個 base64 字符才行。 

 3. 對不足 24 bit (也就是 3 bytes) 的情況進行特殊處理:

  // 只有 1 字節的時候
  if(code.length % 24 === 8){
    // 補齊到 2*6 = 12 bit
    code += '0000';
    // 剩余缺失的 2 個 base64 字符用等號代替
    res += '=='
  }
  // 只有 2 字節的時候
  if(code.length % 24 === 16){
    // 補齊到 3 * 6 = 18 bit
    code += '00';
    // 剩余缺失的 1 個 base64 字符用等號代替
    res += '='
  }

以上,就是一次簡單的 base64 編碼過程了:

var text = "this is a example";

function base64encode(text) {
  let code = '';
  let base64Code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  let res = '';

  for (let i of text) {
    let char = i.charCodeAt().toString(2);
    for (let a = 0; a <= 8 - char.length; a++) {
      char = 0 + char;
    }
    code += char
  }

  if (code.length % 24 === 8) {
    code += '0000';
    res += '=='
  }
  if (code.length % 24 === 16) {
    code += '00';
    res += '='
  }

  let encode = '';
  for (let i = 0; i < code.length; i += 6) {
  let item = code.slice(i, i + 6);
    encode += base64Code[parseInt(item, 2)];
  }

  return encode + res;
}

console.log(base64encode(text)); // dGhpcyBpcyBhIGV4YW1wbGU=

 

我們對於這樣的代碼效率表示不滿意,二進制的操作不應該轉成字符串的加減來達到效果。

三、用位運算簡單優化一下(二進制運算,並且不再拼接字符串,邏輯任然保持一致。)

 

var text = "this is a example";

 

function base64encode(text) {

  let base64Code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  let res = '';
  let i = 0;

 

  while (i < text.length) {
    let char1,char2,char3,enc1,enc2,enc3,enc4;

 

    char1 = text.charCodeAt(i++);
    char2 = text.charCodeAt(i++);
    char3 = text.charCodeAt(i++);

 

    enc1 = char1 >> 2; // 取第 1 字節的前 6 位
    if (isNaN(char2)) {
      // 只有 1 字節的時候
      enc2 = ((char1 & 3) << 4) | (0 >> 4);
      // 第65個字符用來代替補位的 = 號
      enc3 = enc4 = 64;
    } else if (isNaN(char3)) {
      // 只有 2 字節的時候
      enc2 = ((char1 & 3) << 4) | (char2 >> 4);
      enc3 = ((char2 & 15) << 2) | (0 >> 6);
      enc4 = 64;
    }else{
      enc2 = ((char1 & 3) << 4) | (char2 >> 4); // 取第 1 個字節的后 2 位(3 = 11 << 4 = 110000) + 第 2 個字節的前 4 位
      enc3 = ((char2 & 15) << 2) | (char3 >> 6); // 取第 2 個字節的后 4 位 (15 = 1111 << 2 = 111100) + 第 3 個字節的前 2 位
      enc4 = char3 & 63; // 取最后一個字節的最后 6 位 (63 = 111111)
    }
    res += base64Code.charAt(enc1) + base64Code.charAt(enc2) + base64Code.charAt(enc3) + base64Code.charAt(enc4)
  }

 

  return res;
}

 

console.log(base64encode(text));

四、更優的做法 window.btoa

Web Api 其實已經實現了字符串轉 base64 的需求,甚至通過了一些優化,效率會比上面的位運算更優:

  let encodedData = window.btoa("this is a example");
  console.log(encodedData); // dGhpcyBpcyBhIGV4YW1wbGU=

  let decodeData = window.atob(encodedData);
  console.log(decodeData); // this is a example

兼容性方面,已經可以做到 IE 10 以上兼容了。相信在不久的將來就會代替一些手寫庫,漸漸使用上這個內置函數了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM