1、类型化数组定义
JavaScript 类型化数组(typed array)是一种类似数组的对象,并提供了一种用于在内存缓冲区中访问原始二进制数据的机制。
与普通数组的区别:
- 普通数组存储的对象可以动态的增加或减少,并且可以存储任意的 JavaScript
- 类型化数组中的每一个对象都是原始的二进制值,而二进制值采用多种支持的格式之一(从8位整数到64位浮点数)
- 不是所有适用于普通数组的方法都适用与类型化数组(如:push、pop)
2、类型化数组架构
为了达到最大的灵活性和效率,JavaScript 类型化数组将实现拆分为缓冲和视图两部分。
- 缓冲(由 ArrayBuffer 对象实现)描述的是一个数据分块,缓冲没有格式可言,并且不提供访问其内容的机制
- 为了访问在缓冲对象中包含的内存,你需要使用视图。视图提供了上下文——即数据类型、起始偏移量和元素数——将数据转换为实际有类型的数组。
2.1、ArrayBuffer
ArrayBuffer 是一种数据类型,用来表示一个通用的、固定长度的二进制数据缓冲区。
特点:
- 不能直接操作 ArrayBuffer 中的内容
- 需要创建一个类型化数组的视图或一个描述缓冲数据格式的 DataView,使用它们来读写缓冲区中的内容
2.2、类型化数组视图
类型化数组视图具有自描述性的名字和所有常用的数值类型像 Int8、Uint32、Float64 等等。
有一种特殊类型的数组 Uint8ClampedArray,它仅操作 0 到 255 之间的数值。(这对于 Canvas 数据处理非常有用)
类型 | 值范围 | 字节数 | 描述 | 对应的 Web LDL 类型 | 等效的 C 类型 |
---|---|---|---|---|---|
Int8Array | -128~127 | 1 | 8位有符号整数(补码) | byte | int8_t |
Unit8Array | 0~255 | 1 | 8位无符号整数 | octet | unit8_t |
Unit8ClampedArray | 0~255 | 1 | 8位无符号整数(值会被裁剪) | octet | unit8_t |
Int16Array | -32768~32767 | 2 | 16位有符号整数(补码) | short | int16_t |
Unit16Array | 0~65535 | 2 | 16位无符号整数 | unsigned short | unit16_t |
Int32Array | -2147483648~2147483647 | 4 | 32位有符号整数(补码) | long | int32_t |
Unit32Array | 0~4294967295 | 4 | 32位无符号整数 | unsigned long | unit32_t |
Float32Array | -3.4E38~3.4E38 以及 1.2E-38(最小正数) | 4 | 32位 IEEE 浮点数(7位有效数字,例如:1.123456) | unrestricted float | float |
Float64Array | -1.8E308~1.8E308 以及 5E324(最小正数) | 8 | 64位 IEEE 浮点数(16位有效数字,例如:1.123…15) | unrestricted double | double |
BigInt64Array | -263~263-1 | 8 | 64位有符号整数(补码) | bigint | int64_t(signed long long) |
BigUnit64Array | 0~264-1 | 8 | 64位无符号整数 | bigint | unit64_t(unsigned long long) |
2.3、DataView
DataView 是一种底层接口,它提供有可以操作缓冲区中任意数据的访问器(getter/setter)API。这对操作不同类型数据的场景很有帮助,例如:类型化数组视图都是运行在本地字节序模式(参考字节序),可以通过使用 DataView 来控制字节序。默认是大端字节序(Big-endian),但可以调用 getter / setter 方法改为小端字节序(Little-endian)。
3、类型化数组的 Web API
- FileReader.prototype.readAsArrayBuffer():读取对应的 Blob 或 File 的内容
- XMLHttpRequest.prototype.send():XMLHttpRequest 实例的 send() 方法现在支持使用类型化数组和 ArrayBuffer 对象作为参数
- ImageData.data:是一个 Uint8ClampedArray 对象,用来描述包含按照 RGBA 序列的颜色数据的一维数组,其值的范围在 0 到 255 之间
4、使用视图和缓冲
// 创建一个 16 字节固定长度的缓冲
const buffer = new ArrayBuffer(16);
// 判断数据的字节长度
if (buffer.byteLength === 16) {
console.log("Yes"); // 执行,表示 buffer 的长度为16字节
} else {
console.log("No");
}
// 创建一个视图——把缓冲内的数据格式化为一个 32 位有符号整数数组
const int32View = new Int32Array(buffer);
console.log(int32View); // Int32Array [0, 0, 0, 0]
// 向视图中填充数据
for (let i = 0; i < int32View.length; i++) {
int32View[i] = i;
}
console.log(int32View); // Int32Array [0, 1, 2, 3]
// 可以在同一数据上创建多个视图,
const int16View = new Int16Array(buffer);
console.log(int16View); // Int16Array [0, 0, 1, 0, 2, 0, 3, 0]
5、转化为普通数组
// 第一种方法:Array.from()
const typedArray = new Uint8Array([1, 2, 3, 4]);
const normalArray = Array.from(typedArray);
console.log(normalArray); // Array [1, 2, 3, 4]
// 第二种方法:扩展运算符
const typedArray = new Uint8Array([1, 2, 3, 4]);
const normalArray = [...typedArray];
console.log(normalArray); // Array [1, 2, 3, 4]
// 第三种方法:数组原型方法
const typedArray = new Uint8Array([1, 2, 3, 4]);
const normalArray = Array.prototype.slice.call(typedArray);
console.log(normalArray); // Array [1, 2, 3, 4]