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 等效 | 常见用例 |
|---|---|---|---|
| 占位符_0 | 1 字节 | 占位符_1 | 有符号字节数据 |
| 占位符_0 | 1 字节 | 占位符_1 | 原始字节流 |
| 占位符_0 | 1 字节 | 占位符_1 | 画布像素数据 |
| 占位符_0 | 2 个字节 | 占位符_1 | 音频样本 |
| 占位符_0 | 2 个字节 | 占位符_1 | Unicode 代码单元 |
| 占位符_0 | 4 字节 | 占位符_1 | 位图数据 |
| 占位符_0 | 4 字节 | 占位符_1 | 网络数据包 |
| 占位符_0 | 4 字节 | 占位符_1 | 3D 图形 (WebGL) |
| 占位符_0 | 8 字节 | 占位符_1 | 科学计算 |
| 占位符_0 | 8 字节 | 占位符_1 | 大整数 ID |
| 占位符_0 | 8 字节 | 占位符_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 的显式字节序参数消除了所有猜测。
画布像素操作
ImageData 由 Uint8ClampedArray 支持,支持直接像素访问:
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.Memory 由 ArrayBuffer 支持,允许直接内存共享:
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 。

