ES12 中 TypedArray、DataView 进行 buffer 操作的详解

1. TypedArray 与 ArrayBuffer

在 JavaScript 中, 它会将数组等数据存储于连续的内存区域中, 数据的类型和所占用的字节数也在这个过程中被确定。在 ES6 中, 添加了 TypedArray 数据类型来更好地支持二进制数据的处理。

TypedArray 可以看做是 ArrayBuffer 的视图, 它提供了类数组的操作方法, 能够以不同的数据类型访问 ArrayBuffer 的数据。一个 ArrayBuffer 对象表示的其实是一段连续的内存区域,可以直接操作内存。

下面是一个 TypedArray 的例子:

// 创建一个 ArrayBuffer 实例
const buffer = new ArrayBuffer(16);

// 创建一个 Int16Array 实例
const int16Array = new Int16Array(buffer);

// 设置 int16Array 索引为 0 的位置的数据为 1
int16Array[0] = 1;

2. DataView

DataView 实例是用来操作内存中的数据的,它提供了更加灵活的操作方式, 可以操作任意数据类型, 并且还可以指定字节序。因此, DataView 可以解决 TypedArray 无法指定字节序的问题。

下面是一个 DataView 的例子:

// 创建一个 ArrayBuffer 实例
const buffer = new ArrayBuffer(16);

// 创建一个 DataView 实例
const dataView = new DataView(buffer);

// 设置 dataView 索引为 0 的位置的 int16 数据为 1
dataView.setInt16(0, 1);

3. ArrayBuffer 的操作

3.1 获取一个 ArrayBuffer 对象的字节长度

在 JavaScript 中, 可以通过一个 ArrayBuffer 对象的 byteLength 属性获取其字节长度:

const buffer = new ArrayBuffer(16);
console.log(buffer.byteLength); // 输出 16

3.2 截取一个 ArrayBuffer

截取 ArrayBuffer 时, 可以直接使用 slice() 方法, 返回一个从原始 ArrayBuffer 对象中指定起始位置和结束位置的新 ArrayBuffer 对象。

const buffer = new ArrayBuffer(16);
const newBuffer = buffer.slice(4, 12); // 从 buffer 的第 4 字节开始截取,截取 8 个字节

3.3 拼接多个 ArrayBuffer

可以用 TypedArray 中的 set() 方法拼接多个 ArrayBuffer:

// 创建两个包含 int16 类型数据的 TypedArray 实例,每个实例有 2 个元素
const int16Array1 = new Int16Array([1, 2]);
const int16Array2 = new Int16Array([3, 4]);

// 创建一个新的 Int16Array 实例
const newInt16Array = new Int16Array(4);

// 将 int16Array1 和 int16Array2 拼接起来
newInt16Array.set(int16Array1);
newInt16Array.set(int16Array2, 2); // 第二个参数指定从 newInt16Array 的下标 2 开始拼接

console.log(newInt16Array); // 输出 [1, 2, 3, 4]

4. TypedArray 的操作

4.1 创建 TypedArray

TypedArray 对象可以通过传递一个 ArrayBuffer 实例来创建:

const buffer = new ArrayBuffer(16);
const int32Array = new Int32Array(buffer);

4.2 设置 TypedArray 数据

可以将需要的数据直接赋值到 TypedArray 上:

const int16Array = new Int16Array([1, 2]);
int16Array[0] = 3;
console.log(int16Array[0]); // 输出 3

4.3 获取 TypedArray 数据

通过访问方法, 可以获取 TypedArray 对应位数的数据:

const int16Array = new Int16Array([1, 2]);
console.log(int16Array[0]); // 输出 1

4.4 TypedArray 数据类型

在 TypedArray 中, 除了 Int8Array 之外的所有 TypedArray 类, 如 Int16Array、Uint16Array 等都支持以下数据类型:

  • int8
  • uint8
  • int16
  • uint16
  • int32
  • uint32
  • float32
  • float64

4.5 TypedArray 数据的字节长度

默认情况下, TypedArray 中每种数据类型的长度都是固定的, 可以通过 BYTES_PER_ELEMENT 静态属性获取。

const int16Array = new Int16Array([1, 2]);
console.log(Int16Array.BYTES_PER_ELEMENT); // 输出 2

4.6 TypedArray 的迭代器

在 ES6 中, TypedArray 实现了 Symbol.iterator 接口, 因此可以使用 for of 循环遍历数组:

const int16Array = new Int16Array([1, 2]);
for (let x of int16Array) {
    console.log(x);
}
// 输出
// 1
// 2

4.7 TypedArray 的其他方法

TypedArray 还提供了一些其他的方便方法:

  • slice(start : number, end : number): 新的 TypedArray 实例,存储了原 TypedArray 从 start(包括 start)至 end(不包括 end)之间的元素。
  • join(separator?: string): 将 TypedArray 使用指定的分隔符连接为字符串。
  • reverse(): 将 TypedArray 中的元素以相反的顺序排列。
  • sort(compareFn?): 将 TypedArray 中的元素按照指定的顺序排列。

5. DataView 的操作

5.1 获取 DataView 数据

DataView 实例通过访问方法获取对应类型的数据:

const buffer = new ArrayBuffer(16);
const dataView = new DataView(buffer);

// 设置 dataView 中下标为 0 的 int16 数据为 1
dataView.setInt16(0, 1);

// 获取 dataView 中下标为 0 的 int16 类型的数据
console.log(dataView.getInt16(0));

5.2 设置 DataView 数据

DataView 实例通过设置方法设置对应类型的数据:

const buffer = new ArrayBuffer(16);
const dataView = new DataView(buffer);

// 设置 dataView 中下标为 0 的 uint8 类型数据为 255
dataView.setUint8(0, 255);

5.3 DataView 中获取和设置的数据类型

DataView 中可以获取和设置的数据类型如下:

  • getInt8(): 8 位二进制有符号整数
  • getUint8(): 8 位二进制无符号整数
  • getInt16(): 16 位有符号整数
  • getUint16(): 16 位无符号整数
  • getInt32(): 32 位有符号整数
  • getUint32(): 32 位无符号整数
  • getFloat32(): 32 位浮点数
  • getFloat64(): 64 位浮点数

6. 总结

ES12 中的 TypedArray 和 DataView 提供了一种方便、高效的操作二进制数据的方式。在实际应用中, 二者的选择通常由数据是固定长度还是不定长度、需要拼接合并的情况来决定, 以及需要类型控制的程度来选择。

希望本文对于阅读者更好地理解 TypedArray 和 DataView 的操作, 尤其是 buffer 操作方面,能够有一定的参考价值。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65b5e6a9add4f0e0ffea321a