ArrayBuffer


如果要存储一组二进制数据,可以使用ArrayBuffer,它从 ES6 之后成为标准之一,构造ArrayBuffer实例时,必须指定字节长度,例如:

let buf = new ArrayBuffer(32); // 32 个字节
console.log(buf.byteLength);  // 显示 32

你没办法直接改变ArrayBuffer实例的内容,只能透过byteLength特性获取长度,slice方法切割ArrayBuffer

若要改变或获取ArrayBuffer内容,方式之一是透过TypedArray,有以下几个子类型:

  • Int8Array:8 位有符号整数,长度一字节
  • Uint8Array:8 位无符号整数,长度一字节
  • Uint8ClampedArray:8 位无符号整数,长度一字节,超出 [0, 255] 的值,会设定为 0 或 255。
  • Int16Array:16 位有符号整数,长度二字节。
  • Uint16Array:16 位无符号整数,长度二字节。
  • Int32Array:32 位有符号整数,长度四字节。
  • Uint32Array:32 位无符号整数,长度四字节。
  • Float32Array:32 位浮点数,长度四字节。
  • Float64Array:64 位浮点数,长度八字节。

不同的TypedArray子类型,检视、操作ArrayBuffer的观点(View)不同,例如同一个ArrayBuffer实例,在不同的TypedArray观点下,每个元素的位长度不同,因而透过length获取元素个数也就不同:

let buf = new ArrayBuffer(32);
let i8arr = new Int8Array(buf);
let i16arr = new Int16Array(buf);
let i32arr = new Int32Array(buf);

console.log(i8arr.length);  // 显示 32
console.log(i16arr.length); // 显示 16
console.log(i32arr.length); // 显示 8

buf有 32 个字节,也就是 256 个位,就Int8Array来说,8 个位为一个元素,因此会有 32 个元素,就Int16Array来说,16 位为一个元素,因而会有 16 个元素,同样地,对Int32Array来说,会有 8 个元素。

在设定元素时,对每个元素的观点,也视不同的TypedArray子类型而不同,例如,透过Uint8Array来写入与读出:

let buf = new ArrayBuffer(5);
let ui8arr = new Uint8Array(buf);
ui8arr[0] = 72;  // H
ui8arr[1] = 101; // e
ui8arr[2] = 108; // l
ui8arr[3] = 108; // l
ui8arr[4] = 111; // 0

// 显示 Hello
console.log(String.fromCharCode.apply(null, ui8arr));

在构造TypedArray子类型时,也可以使用类数组对象,例如:

let ui8arr = new Uint8Array([72, 101, 108, 108, 111]);

// 显示 Hello
console.log(String.fromCharCode.apply(null, ui8arr));

在构造TypedArray之后,操作方法和特性,与Array几乎是完全相同的,可参考TypedArray API 文件

TypedArray的子类型,对待每个元素的观点是一致的,如果数据中包含了不同类型的元素,例如,同时包含了 8 位整数与 16 位整数,可以使用DataView来处理:

let buf = new ArrayBuffer(3);
let dataView =  new DataView(buf);

dataView.setInt16(0, 72);
dataView.setInt8(2, 105);

console.log(dataView.getInt16(0));
console.log(dataView.getInt8(2));

由于数据长度不固定,在调用setXXXgetXXX时,必须指定字节偏移量。


展开阅读全文