pikou1995 / pikou1995.github.io

My Github Page
4 stars 1 forks source link

理解javascript中的binary string #15

Open pikou1995 opened 3 years ago

pikou1995 commented 3 years ago

相信大家都知道 base64,浏览器有内置的方法 atobbtoa,这里面的 a 表示 ascii,b 表示 binary string。

你知道为什么 atob 有时候返回的结果像乱码吗?

image

你知道为什么 btoa 有时候会报错 InvalidCharacterError: The string contains invalid characters. 吗?

image

binary string 的定义

binary string 是 JS 字符集的一个子集,它的码点(charCode)限制到 255,它包含了 255 以内的字符。binary string 设计的目的不是用于代表字符, 而是代表二进制数据。

这样理解很抽象,我们通过几个例子来解释一下。

const binStr = "a";

如果说这个变量是 binary string,那么它表示的就不是字母 a,而是 uint8 类型的 97。可能这个例子让人有点糊涂,那 \u0000 表示 uint8 类型的 0 应该更容易理解,因为此字符是不可见的。

那这么麻烦,为什么不直接用 97 来表示呢? [97,98,99,100] 是可以保存,但是序列化之后占的空间比 "abcd" 要高出不少,以 utf-8,json 格式保存,前者是 14 个字节,后者是 6 个字节(4+表示字符串的两个双引号)。

转换

binStr.charCodeAt(0); // 97
new TextEncoder().encode(binStr); // Uint8Array [97]

node 环境还可以用 Buffer, 不过结果是 hex 的

Buffer.from(binStr, "binary"); // <Buffer 61>
0x61 === 97; // true

空间占用

在 js 内存中,由 binary string 代表的二进制数据大小是原始数据的两倍,因为现在的 es6 用的是 utf-16 编码,0-255对应的码点占用两个字节。而序列化为 utf-8 就会节省一些空间,按 utf-8 编码,0-127 占一个字节,128-255 占两个字节。

总结

atob 有时候返回的结果像乱码一样,是因为返回的结果是为了表示二进制数据。

btoa 有时候会报错是因为传进去的参数码点大于 255 。