【深入 Base64】Javascript 实现 Base64 编解码(五)

上一篇博客已经用纯 JS 实现了 Base64 的编解码处理,本来这个系列应该结束了,但是呢,人总是喜欢琢磨的,今天我要介绍另外一种更加另类、更加简单的处理方式。这里就要用到我们前面提到的 escape、unescape、encodeURI 和 decodeURI 这几个方法。关于这几个方法的作用我这里不做说明,想了解的可以去看我前面的博文。

 思路

其实整体思路和上一篇一样,要把字符串转成一个个单字节字符。上一篇我们自己手写了一个 unicode2utf8 的函数,今天我们就不用自己手写了,用 encodeURI 函数就能实现,因为这个函数就是把 Javascript 中的 unicode 字符串转成类似于 "%E9%A3%8E" 的 utf-8 编码字符串。

然后就是把 utf-8 编码转成单字节字符,这里用到了 unescape 函数,这个函数会把 "%xx" 的十六进制编码字符串转成 ASCII 字符;把 "%uxxxx" 转成双字节 unicode 字符。

实现

这一篇博文其实就是把上一篇博文的 unicode2utf8 和 utf82unicode 这两个函数用 JS 中自带的方法去实现了。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Javascipt 实现 Base64 编解码</title>
</head>
<body>
<div>
    <span>输入要编码的字符串</span>
    <input type="text" id="input">
</div>
<div>
    <span>Base64 编码:</span>
    <span id="enBase64"></span>
</div>
<div>
    <span>Base64 解码:</span>
    <span id="deBase64"></span>
</div>
<script>
    // 一般的Base64编码字符
    var commonbase64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    // 对URL进行编码使用的字符
    var urlBase64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";

    /*
     Base64 是以字节为单位处理,所以我们处理的字符串应该是单字节字符串
     这里我们默认是 utf-8 编码的字符串,因为 JS 无法识别 UTF-8 编码字符串,会识别成一个个单字节字符串
     */
    function encodeBase64(hexStr){
        var len = hexStr.length,
                h1, h2, h3,
                outStr = "";

        for (var i = 0; i < len; i++) {
            h1 = hexStr.charCodeAt(i);

            if(i == len){ // 最后一个字符
                outStr += commonbase64EncodeChars.charAt(h1 >> 2);
                outStr += commonbase64EncodeChars.charAt((h1 << 4) & 0x3F);
                outStr += "==";
            } else if (i == len - 1) { // 倒数第二个字符
                h2 = hexStr.charCodeAt(++i);
                outStr += commonbase64EncodeChars.charAt(h1 >> 2);
                outStr += commonbase64EncodeChars.charAt(((h1 << 4) & 0x3F) | (h2 >> 4));
                outStr += commonbase64EncodeChars.charAt((h2 << 2) & 0x3F);
                outStr += "=";
            } else { // 剩余大于二个字符
                h2 = hexStr.charCodeAt(++i);
                h3 = hexStr.charCodeAt(++i);
                outStr += commonbase64EncodeChars.charAt(h1 >> 2);
                outStr += commonbase64EncodeChars.charAt(((h1 << 4) & 0x3F) | (h2 >> 4));
                outStr += commonbase64EncodeChars.charAt((h2 << 2) & 0x3F | (h3 >> 6));
                outStr += commonbase64EncodeChars.charAt(h3 & 0x3F);
            }
        }

        return outStr;
    }

    function decodeBase64(str) {
        var str = filterBase64(str),
                len = str.length,
                h1, h2, h3, h4,
                outStr = "";

        for (var i = 0; i < len;) {
            h1 = commonbase64EncodeChars.indexOf(str.charAt(i++));
            h2 = commonbase64EncodeChars.indexOf(str.charAt(i++));
            h3 = commonbase64EncodeChars.indexOf(str.charAt(i++));
            h4 = commonbase64EncodeChars.indexOf(str.charAt(i++));

            outStr += String.fromCharCode((h1 << 2) | (h2 >> 4));
            if (h3) outStr += String.fromCharCode(((h2 << 4) & 0xF0) | (h3 >> 2));
            if (h4) outStr += String.fromCharCode(((h3 << 6) & 0xC0) | h4);
        }

        return outStr;
    }

    function filterBase64(str) {
        var len = str.length,
                c,
                outStr = "";

        for (var i = 0; i < len; i++) {
            c = str.charAt(i);
            if (commonbase64EncodeChars.indexOf(c) != -1) {
                outStr += c;
            }
        }

        return outStr;
    }

    document.querySelector("#input").addEventListener("input", function () {
        var inputStr = this.value;
        var encodeBase64Str = encodeBase64(unescape(encodeURI(inputStr)));
        var decodeBase64Str = decodeURI(escape(decodeBase64(encodeBase64Str)));

        document.querySelector("#enBase64").innerText = encodeBase64Str;
        document.querySelector("#deBase64").innerText = decodeBase64Str;
    })
</script>
</body>
</html>