Javascript Base64 atob 与 btoa 方法之 a b 探究
Javascript 实现 Base64 编码和解码
var cod = {
ut8: {
enc: TextEncoder.prototype.encode.bind(new TextEncoder()),
dec: TextDecoder.prototype.decode.bind(new TextDecoder()),
},
b64: {
enc: str => btoa(String.fromCodePoint(...cod.ut8.enc(str))),
dec: a64 => cod.ut8.dec(Uint8Array.from(atob(a64), c=>c.codePointAt(0))),
},
};
// use it for base64 encode/decode
var {enc, dec} = cod.b64;
console.log(enc("汉字china")); // "5rGJ5a2XY2hpbmE="
console.log(dec(enc("汉字china"))); // "汉字china"
atob 与 btoa 的 a b 探究
- 要弄清这个问题,最好结合mdn原文,进行读解:
mdn原文:https://developer.mozilla.org/en-US/docs/Glossary/Base64 - 注意其中的"NOTE"部分:
Base64 is a binary encoding rather than a text encoding,
Base64是 二进制编码 而不是 文本编码 ,
啥
Base64
是
二进制编码
?! …
懵了吧! - 别急,继续看:
“atob” should be read as “ASCII to binary”
“atob”应读作“ASCII转二进制”
“btoa” should be read as “binary to ASCII”
“btoa”应读作“二进制转ASCII” - 还是懵吧!
原文意思是:
这里的"b",不是代表"Base64",而是"Binary",
而代表"Base64"编码的,反而是这里的"a",即:
a= “5rGJ5a2XY2hpbmE=”
体会到反直觉了么? - 继续:
the two functions use strings to represent binary data,
这两个函数使用字符串来 表示 二进制数据, - 这就有点意思了,继续:
the code point of each character representing the value of each byte.
每个字符的 代码点 表示每个字节的值。 - get 到关键点了, “code point” 就是这个关键点:
试试以下代码:
// 为条理清晰,使用我上篇文章的Promise知识点写出base64的编解码代码
Promise.resolve("汉字china")
// string 按utf8编码方式转 bytes(uint8arr)
.then( TextEncoder.prototype.encode.bind(new TextEncoder()) )
// bytes 查表转 bytesASCII,这个 bytesASCII 就是上面讨论的"b"
.then( bytes => String.fromCodePoint(...bytes) ) //"bytesASCII"="ä¸å›½china"
// btoa ---> bytesASCII 转 ASCII64(base64)
.then( btoa )
.then( ascii64 => console.log(ascii64) || ascii64 )
.then( atob )
.then( bytesASCII => Uint8Array.from(bytesASCII, char => char.codePointAt(0)) )
.then( TextDecoder.prototype.decode.bind(new TextDecoder()) )
.then( string => console.log(string) || string )
;
其实 “a” 中的ASCII码,只用了其中 64个可见字符,即基于64个字符的编码方式,这也是Base64名称的由来。
- Base64 与 String 互转解析:
1、“a”:特定的64个可见ASCII码符,干脆叫 “ASCII64” 码符,好对应 “a”
2、“b”:0~255的ASCII码符,与 “bytes” 数值一一对应,别名 “bytesASCII”,好对应 “b”
3、“atob”:“ASCII64 to bytesASCII”
4、“btoa”:“bytesASCII to ASCII64”
5、“Uint8Array”:干脆叫 “bytes”
6、查表互转"bytes" 和 “bytesASCII”:
“String.fromCodePoint”:用数值串查出对应字符串
“char.codePointAt(0)”:用字符查出对应数值,单个进行
7、String/Base64互转:string <=> bytes <=> bytesASCII <=> ASCII64
把 Base64 当成 Ascii64 理解 你就不会混淆 atob 和 btoa 了
附上上段代码的完整带参版,思路更清晰些:
Promise.resolve("汉字china")
.then( string => TextEncoder.prototype.encode.bind(new TextEncoder())( string) )
.then( bytes => String.fromCodePoint(...bytes) )
.then( bytesASCII => btoa( bytesASCII) )
.then( ascii64 => console.log( '编码结果:',ascii64) || ascii64 )
.then( ascii64 => atob( ascii64) )
.then( bytesASCII => Uint8Array.from( bytesASCII, char => char.codePointAt(0)) )
.then( bytes => TextDecoder.prototype.decode.bind(new TextDecoder())( bytes) )
.then( string => console.log( '解码结果:',string) || string )
;