ArrayBuffer
对象代表储存二进制数据的一段内存,它不能直接读写,只能通过视图(TypedArray
视图和DataView
视图)来读写,视图的作用是以指定格式解读二进制数据。const buf = new ArrayBuffer(32);
上面代码生成了一段 32 字节的内存区域,每个字节的值默认都是 0
const buffer = new ArrayBuffer(12);
const x1 = new Int32Array(buffer);
x1[0] = -434393088;
查看buffer内容
其中[[Int32Array]]=[-434393088,0,0];
每个位置占4个字节,接下来我们看下其他几个是怎么得出来的
[[Int8Array]]: Int8Array(12) [0, -80, 27, -26, 0, 0, 0, 0, 0, 0, 0, 0]
[[Int16Array]]: Int16Array(6) [-20480, -6629, 0, 0, 0, 0]
[[Uint8Array]]: Uint8Array(12) [0, 176, 27, 230, 0, 0, 0, 0, 0, 0, 0, 0]
负数在计算机中的存储是以补码存储的
原码求补码
正整数的补码是其二进制表示,与原码相同
负整数的补码,将其原码除符号位外的所有位取反(0变1,1变0,符号位为1不变)后加1
接下来我们看下-434393088的补码是多少
-434393088对应原码
(1001 1001 1110 0100 0101 0000 0000 0000)→
所有位取反(1110 0110 0001 1011 1010 1111 1111 1111)
→补码=加1(1110 0110 0001 1011 1011 0000 0000 0000);
计算机都采用小端字节序(little endian),相对重要的字节排在后面的内存地址,相对不重要字节排在前面的内存地址,所以就得到了上面的结果
所以-434393088的存储是 0000 0000 1011 0000 0001 1011 1110 0110
接着分析[[Int8Array]]结果:
[[Int8Array]]: Int8Array(12) [0, -80, 27, -26, 0, 0, 0, 0, 0, 0, 0, 0]
第一个字节是0,没问题.
第二个字节是1011 0000,1开始的判断为负数,负数存储的是补码所以求其原码 (1011 0000)补码 =>反码减1 (1010 1111) =>取反为原码(1101 0000) 即-80
第三个字节0001 1011 以0开始所以是正数为27
第四个字节1110 0110,1开始的判断为负数,负数存储的是补码所以求其原码 (1110 0110)补码 =>反码减1 (1110 0101) =>取反为原码(1001 1010) 即-26;
接下来分析[[Int16Array]]结果:
[[Int16Array]]: Int16Array(6) [-20480, -6629, 0, 0, 0, 0],Int16占用2个字节,读取时两个字节
第一个结果是(0000 0000 1011 0000 ),又由于采用小端存储取出结果为
(1011 0000 0000 0000 )
1开始的判断为负数,负数存储的是补码所以求其原码 (1011 0000 0000 0000)补码 =>反码减1 (1010 1111 1111 1111) =>取反为原码(1101 0000 0000 0000) 即-20480;
第二个结果是(0001 1011 1110 0110 ),又由于采用小端存储取出结果为
(1110 0110 0001 1011)
1开始的判断为负数,负数存储的是补码所以求其原码 (1110 0110 0001 1011)补码 =>反码减1 (1110 0110 0001 1010) =>取反为原码(1001 1001 1110 0101) 即-6629;
接着分析[[Uint8Array]]结果:
[[Uint8Array]]: Uint8Array(12) [0, 176, 27, 230, 0, 0, 0, 0, 0, 0, 0, 0]
每个占用一个字节,又是无符号位,所以不存在负数,相对来说比较简单
0000 0000 1011 0000 0001 1011 1110 0110
得到0 得到176 得到27 得到230
这样就能搞清楚ArrayBuffer
ArrayBuffer 与字符串的互相转换
function str2ab(input){
const encoder = new TextEncoder()
const view = encoder.encode(input)
return view
}
根据Unicode和UTF-8关系
Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
----------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
根据上面的关系,写下buffer转换为UTF-8
function ab2str(input){
let strArr=[];
for(let i=0;i<input.length;){
let charcode0=input[i] & 0b11111000;
if(charcode0==240){
let str4=(input[i] & 0b00000111)<<18;
let str3=(input[i+1] & 0b00111111)<<12;
let str2=(input[i+2] & 0b00111111)<<6;
let str1=(input[i+3] & 0b00111111);
strArr.push(String.fromCharCode(str4+str3+str2+str1));
i+=4;
continue;
}
charcode0=input[i] & 0b11110000;
if(charcode0==224){
let str3=(input[i] & 0b00001111)<<12;
let str2=(input[i+1] & 0b00111111)<<6;
let str1=(input[i+2] & 0b00111111);
strArr.push(String.fromCharCode(str3+str2+str1));
i+=3;
continue;
}
charcode0=input[i] & 0b11100000;
if(charcode0==192){
let str2=(input[i] & 0b00011111)<<6;
let str1=(input[i+1] & 0b00111111);
strArr.push(String.fromCharCode(str2+str1));
i+=2;
continue;
}
charcode0=input[i];
if(charcode0<=127){
strArr.push(String.fromCharCode(input[i]));
i+=1;
continue;
}
};
return strArr.join("");