ArrayBuffer是什么

预计阅读时间: 5 分钟
"ArrayBuffer

ArrayBufferJavaScript 中用于存储二进制数据的对象。它是一个固定长度的原始二进制数据缓冲区,不能直接操作其中的数据,需要通过其他对象(如 TypedArrayDataView)来访问和操作。

其中有几个关键点:

  • 固定长度
  • 原始二进制数据,也是0和1
  • 不能直接操作, 需要通过其他对象(如 TypedArrayDataView)来访问和操作
"ArrayBuffer与Array 的区别

ArrayBufferArray 没有任何关系:

  1. 它的长度是固定的,我们无法增加或减少它的长度。
  2. 它正好占用了内存中的那么多空间。
  3. 要访问单个字节,需要另一个“视图”对象,而不是 buffer[index]

ArrayBuffer 的用途

ArrayBuffer 通常用于处理二进制数据,例如:

  • 读取和写入文件
  • 处理网络协议
  • 加密和解密
  • 数据传输和存储

如在3D渲染中,ArrayBuffer 可以用于存储顶点数据、法向量、纹理坐标等。gltf格式的模型文件,bin文件就可以使用ArrayBuffer来存储。

ArrayBuffer 的创建

main.js
1let buffer = new ArrayBuffer(16); // 创建一个长度为 16 的 buffer
2alert(buffer.byteLength); // 16
3// 它会分配一个 16 字节的连续内存空间,并用 0 进行预填充。
4// 以字节为单位,每个字节是8位二进制,所以16字节就是128位

TypedArray

TypedArrayArrayBuffer 的视图,它提供了对缓冲区内容的类型化访问。

"TypedArray

视图对象 是操作 ArrayBuffer的工具,本身并不存储任何东西,而是通过它的规则解释存储在 ArrayBuffer中的字节

TypedArray的类型

  • Uint8ArrayArrayBuffer 中的每个字节视为 0 到 255 之间的单个数字(每个字节是 8 位,因此只能容纳那么多)。这称为 【8 位无符号整数】。
  • Uint16Array 将每 2 个字节视为一个 0 到 65535 之间的整数。这称为 【16 位无符号整数】。
  • Uint32Array 将每 4 个字节视为一个 0 到 4294967295 之间的整数。这称为 【32 位无符号整数】。
  • Float64Array 将每 8 个字节视为一个 5.0x10^-324^1.8x10^308^之间的浮点数。

arraybuffer

因此,一个 16 字节 ArrayBuffer 中的二进制数据可以解释为 16 个“小数字”,或 8 个更大的数字(每个数字 2 个字节),或 4 个更大的数字(每个数字 4 个字节),或 2 个高精度的浮点数(每个数字 8 个字节)

TypedArray属性和方法

1. 创建方法
main.js
1// 以上的几种类型数组,都有以下5中函数重载的实现,Uint32Array
2new TypedArray(buffer, [byteOffset], [length]);  // 除了提供buffer外,其他情况都会创建新的buffer
3new TypedArray(object);
4new TypedArray(typedArray);
5new TypedArray(length);
6new TypedArray();
2. 属性
  • arr.buffer —— 引用 ArrayBuffer。
  • arr.byteLength —— ArrayBuffer 的长度
3. 越界行为

对于越界值,会采用仅保留最右位,多余的位被切除的操作 越界行为

Uint8ClampedArray 在这方面比较特殊,它的表现不太一样。对于大于 255 的任何数字,它将保存为 255,对于任何负数,它将保存为 0。此行为对于图像处理很有用。

4. 方法

TypedArray 具有常规的 Array 方法,但有个明显的例外。我们可以遍历(iterate),map,slice,findreduce 等。

"TypedArray 的限制

但有几件事我们做不了:

  • 没有 splice —— 我们无法“删除”一个值,因为类型化数组是缓冲区(buffer)上的视图,并且缓冲区(buffer)是固定的、连续的内存区域。我们所能做的就是分配一个零值。
  • concat 方法。

还有两种其他方法:

main.js
1arr.set(fromArr, [offset]) 
2 // 从 offset(默认为 0)开始,将 fromArr 中的所有元素复制到 arr。
3 arr.subarray([begin, end]) 
4 // 创建一个从 begin 到 end(不包括)相同类型的新视图。这类似于 slice 方法(同样也支持),但不复制任何内容 —— 只是创建一个新视图,以对给定片段的数据进行操作。

DataView ——更灵活的TypedArray

DataView 是在 ArrayBuffer 上的一种特殊的超灵活“未类型化”视图。它允许以任何格式访问任何偏移量offset的数据。

"DataView
  • 对于类型化的数组,构造器决定了其格式。整个数组应该是统一的。第 i 个数字是 arr[i]。
  • 通过 DataView,我们可以使用 .getUint8(i).getUint16(i) 之类的方法访问数据。我们在调用方法时选择格式,而不是在构造的时候。
main.js
1new DataView(buffer)
2new DataView(buffer, byteOffset)
3new DataView(buffer, byteOffset, byteLength)
4
5// buffer —— 底层的 ArrayBuffer。与类型化数组不同,DataView 不会自行创建缓冲区(buffer)。我们需要事先准备好。
6// byteOffset —— 视图的起始字节位置(默认为 0)。
7// byteLength —— 视图的字节长度(默认至 buffer 的末尾)。
main.js
1// 4 个字节的二进制数组,每个都是最大值 255
2let buffer = new Uint8Array([255, 255, 255, 255]).buffer;
3
4let dataView = new DataView(buffer);
5
6// 在偏移量为 0 处获取 8 位数字
7alert( dataView.getUint8(0) ); // 255
8
9// 现在在偏移量为 0 处获取 16 位数字,它由 2 个字节组成,一起解析为 65535
10alert( dataView.getUint16(0) ); // 65535(最大的 16 位无符号整数)
11
12// 在偏移量为 0 处获取 32 位数字
13alert( dataView.getUint32(0) ); // 4294967295(最大的 32 位无符号整数)
14
15dataView.setUint32(0, 0); // 将 4 个字节的数字设为 0,即将所有字节都设为 0

通过 DataView ,就可以更自由操作二进制数字了