Featured image of post JavaScript 类型数组:浏览器中的二进制数据处理Featured image of post JavaScript 类型数组:浏览器中的二进制数据处理

JavaScript 类型数组:浏览器中的二进制数据处理

掌握用于二进制数据处理的 JavaScript 类型数组:ArrayBuffer、TypedArray 视图、DataView、字节序、WebAssembly 集成和 Canvas 像素操作。

JavaScript 的原生 Number 类型(IEEE 754 双精度浮点数)对于二进制数据来说效率低下。早期的解决方案涉及在普通数组中手动​​打包字节,这种方法速度慢且容易出错。 ECMAScript 2015 正式化了类型数组,为 JavaScript 带来了类似 C 的内存管理。这种三层架构 — ArrayBuffer、TypedArray 视图和 DataView — 支持在浏览器和 Node.js 中进行高性能二进制数据处理。

ArrayBuffer基金会

ArrayBuffer 表示固定长度的原始二进制缓冲区。它不能直接读取或写入 - 您必须使用视图:

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

缓冲区可以使用 structuredClone 在 Web Worker 之间传输,或者使用 resizable 标志调整大小。 slice() 方法创建部分副本。重要的是,缓冲区本身没有类型信息——它只是一个连续的内存块。


类型化数组视图

类型化数组视图为 ArrayBuffer 提供了一个类型化窗口。每个视图将缓冲区的字节解释为特定数字类型的元素:

const buffer = new ArrayBuffer(8);
const int32 = new Int32Array(buffer);    // 2 × 32-bit integers
const float64 = new Float64Array(buffer); // 1 × 64-bit float

以下是类型化数组类型及其特征的完整参考:

构造函数元素尺寸C 等效常见用例
占位符_01 字节占位符_1有符号字节数据
占位符_01 字节占位符_1原始字节流
占位符_01 字节占位符_1画布像素数据
占位符_02 个字节占位符_1音频样本
占位符_02 个字节占位符_1Unicode 代码单元
占位符_04 字节占位符_1位图数据
占位符_04 字节占位符_1网络数据包
占位符_04 字节占位符_13D 图形 (WebGL)
占位符_08 字节占位符_1科学计算
占位符_08 字节占位符_1大整数 ID
占位符_08 字节占位符_1密码学

创建子数组而不进行复制使用 subarray()

const full = new Uint8Array([10, 20, 30, 40]);
const partial = full.subarray(1, 3);  // [20, 30] — zero copy

复杂结构的数据视图

当缓冲区包含混合数据类型时,DataView 提供您所需的灵活性。它允许以显式类型和字节顺序以任意字节偏移量进行读写:

const buffer = new ArrayBuffer(8);
const dv = new DataView(buffer);
dv.setUint16(0, 0x4D42, true);  // little-endian 'BM' signature
dv.setUint32(2, 1024, true);    // file size
dv.setUint16(6, 54, true);      // pixel offset

littleEndian 参数对于跨平台兼容性至关重要。由于其灵活性,DataView 比类型化视图稍慢,但它是解析 BMP、PNG 或 WAV 标头等二进制文件格式的正确工具。


字节序和跨平台处理

Endianness 指的是字节顺序:big-endian 首先存储最高有效字节,little-endian 首先存储最低有效字节。您可以在运行时检测平台字节顺序:

const isLittleEndian = new Uint16Array(
  new Uint8Array([0x12, 0x34]).buffer
)[0] === 0x3412;

在使用网络协议(TCP、WebSocket 二进制帧)、文件格式(PNG、WAV、MP4)和 WebGPU 缓冲区布局时,字节顺序很重要。 DataView 的显式字节序参数消除了所有猜测。


画布像素操作

ImageDataUint8ClampedArray 支持,支持直接像素访问:

const ctx = canvas.getContext("2d");
const imageData = ctx.getImageData(0, 0, width, height);
const pixels = imageData.data;  // Uint8ClampedArray

for (let i = 0; i < pixels.length; i += 4) {
  const gray = 0.299 * pixels[i] + 0.587 * pixels[i+1] + 0.114 * pixels[i+2];
  pixels[i] = pixels[i+1] = pixels[i+2] = gray;  // grayscale
}
ctx.putImageData(imageData, 0, 0);

这种方法比画布过滤器方法要快得多,并且可以通过 requestAnimationFrame 实现实时视频处理。


WebAssembly 内存集成

类型化数组是 JavaScript 和 WebAssembly 之间的桥梁。 WebAssembly.MemoryArrayBuffer 支持,允许直接内存共享:

const memory = new WebAssembly.Memory({ initial: 1 });  // 1 page = 64KB
const buffer = memory.buffer;
const view = new Uint8Array(buffer);
// Write data, call Wasm function, read results

这种零拷贝模型是高性能 WebAssembly 应用程序的基础。


性能优化

对于数值数据,类型化数组比普通数组具有显着的性能优势。使用 new ArrayBuffer(expectedSize) 预分配缓冲区以避免调整大小。使用 subarray() 而不是 slice() 以避免复制。通过保持类型化数组访问单态来避免隐藏类转换。对于算术密集型代码,Float64Array 利用 CPU 的本机双精度管道。

掌握使用类型化数组进行二进制数据处理可以解锁应用领域,包括音频/视频处理、WebAssembly、游戏开发和科学计算。对于混合类型解析,请使用 DataView。对于统一数值数组,请使用类型化视图。对于原始内存管理,直接使用 ArrayBuffer