浅谈JavaScript中的ArrayBuffer
什么是ArrayBuffer
ArrayBuffer是一个用于存储二进制数据的类,它提供了一种方法来表示字节序列,这些字节可以表示各种数据类型,如整数、浮点数、字符串等。ArrayBuffer是一个不可变的数据结构,它不能被修改,但可以通过创建一个TypedArray或DataView来修改它的内容。
知识点
- 对内存中固定长度的、连续的、二进制数据的、引用
- ArrayBuffer要当做Buffer理解,不能当做Array理解,因为它不具备任何Array的常用的方法;叫ArrayBuffer估计是因为它表示的是内存中连续的数据。
- ArrayBuffer的大小固定,不能动态扩展。
- ArrayBuffer不能直接操作,需要使用TypedArray或DataView来操作。
花式操作ArrayBuffer
ArrayBuffer不能直接操作,需要使用TypedArray或DataView来操作。三者关系如下:
ArrayBuffer、TypedArray、DataView关系
TypedArray
TypedArray 是一组用于操作 ArrayBuffer 的类型化数组。 它们允许你以特定的数据类型(例如:整数、浮点数)来读取和写入 ArrayBuffer 中的数据。包含如下类型:
- 1. Int8Array: 8 位有符号整数数组。
- 2. Uint8Array: 8 位无符号整数数组。
- 3. Uint8ClampedArray: 8 位无符号整数数组,但当赋值超出范围时会被自动调整到 0 或 255。
- 4. Int16Array: 16 位有符号整数数组。
- 5. Uint16Array: 16 位无符号整数数组。
- 6. Int32Array: 32 位有符号整数数组。
- 7. Uint32Array: 32 位无符号整数数组。
- 8. Float32Array: 32 位浮点数数组。
- 9. Float64Array: 64 位浮点数数组。
TypedArray 还有set、subarray等方法,但没有splice、concat方法。具体可查阅相关文档。
使用TypedArray操作ArrayBuffer
let buffer = new ArrayBuffer(16);
console.log(buffer); // 长度16
let int8 = new Int8Array(buffer);
console.log(int8); // 长度16
let int16 = new Int16Array(buffer);
console.log(int16); // 长度8
let int32 = new Int32Array(buffer);
console.log(int32); // 长度4
let float64 = new Float64Array(buffer);
console.log(float64); // 长度2
结合这个图理解上面代码的运行结果
不同的TypedArray的赋值操作
由上图可以知道,ArrayBuffer的长度和Uint8Array的长度是相同的,所以可以认为对Uint8Array的操作和ArrayBuffer对应位置一一对应,不再赘述。
let buffer = new ArrayBuffer(16);
let uint8 = new Uint8Array(buffer);
uint8[0] = 255;
console.log(uint8,uint8.buffer);
以Unit16为例,一个Unit16占两个字节,一个字节8个bit;而ArrayBuffer一个位置对应一个字节.所以当uint16[0] = 258时,其16个bit位为:00000001 00000010,存储在ArrayBuffer中时,会占据两个字节的位置[2,1],
let buffer = new ArrayBuffer(2);
/*let uint8 = new Uint8Array(buffer);
uint8[0] = 255;
console.log(uint8,uint8.buffer);*/
let uint16 = new Uint16Array(buffer);
uint16[0] = 258;
console.log(uint16,uint16.buffer);// [258] , [2,1]
需要注意的对应的位置,从二进制数的低位开始,每8个bit位对应一个字节,可以参考下图理解:
32位、64位同理,大家可以尝试一下。
DataView
DataView 提供了更灵活的方式来读取和写入 ArrayBuffer 中的数据。 它可以让你以任意字节偏移量和数据类型来访问数据,而无需像 TypedArray 那样必须从缓冲区的开头开始。
let buffer = new ArrayBuffer(4);
let dv = new DataView(buffer);
dv.setUint16(1,258);
console.log(dv.getUint16(1),dv.getUint16(0),dv.buffer);// 输出258,1,[0,1,2,0];
DataView 根据不同的方法决定操作的字节数,以上述的setUint16(1,258)为例,表示从索引为1的位置开始,操作连续两个字节的数据,数据范围为0-65535,258的二进制为00000001 00000010,所以这两个字节为[1,2];getUint16(1),表示从索引1开始连续读两个字节[00000001,00000010],所以输出为258;getUint16(0),表示从索引0开始连续读两个字节[00000000,00000001],所以输出为1。整个ArrayBuffer为[0,1,2,0],可以发现,填入的顺序和TypedArray的顺序是相反的。32位、64位大家可以自行尝试一下。可以参考下图理解: