JavaScript 的类型化数组(Typed Arrays)

JavaScript 的类型化数组(Typed Arrays)是一种用于高效处理二进制数据(即原始字节或数值)的机制。它们不是传统意义上的数组,而是一组基于 ArrayBuffer 的视图(views),允许你以特定的数据类型(如 8 位整数、32 位浮点数等)来读写底层的二进制缓冲区。


1. 背景:为什么需要类型化数组?

  • JavaScript 原生的 Array 是动态、松散类型的,不适合高性能数值计算或与二进制数据(如图像、音频、网络协议、WebAssembly 等)交互。
  • 类型化数组提供固定类型、固定长度、连续内存布局的结构,性能更高,内存更可控。

2. 核心概念

为了最大程度的灵活性和效率,JavaScript 将类型化数组的实现拆分为缓冲和视图两部分。
缓冲是一种表示了数据块的对象,它没有格式可言,也没有提供访问其内容的机制。为了访问缓冲中的内存,你需要使用视图

ArrayBuffer

  • 表示一块原始的二进制数据缓冲区
  • 本身不能直接读写,必须通过 视图(TypedArray 或 DataView)来访问。
const buffer = new ArrayBuffer(16); // 1分配 16 字节内存

✅ 类型化数组视图(TypedArray)

  • ArrayBuffer特定类型视图
  • 常见类型包括:
    类型 元素大小(字节) 取值范围
    Int8Array 1 -128 ~ 127
    Uint8Array 1 0 ~ 255
    Uint8ClampedArray 1 0 ~ 255(溢出时自动钳制)
    Int16Array 2 -32768 ~ 32767
    Uint16Array 2 0 ~ 65535
    Int32Array 4 -2³¹ ~ 2³¹−1
    Uint32Array 4 0 ~ 2³²−1
    Float32Array 4 单精度浮点数
    Float64Array 8 双精度浮点数(JS 默认 Number)

所有类型化数组共享相同的 API(类似数组,有 length、可索引,但不是 Array 的实例)。

示例:

const buffer = new ArrayBuffer(8);
const int32View = new Int32Array(buffer); // 用 32 位整数视角看 buffer
int32View[0] = 100;
int32View[1] = -50;

console.log(int32View.length); // 2(8 字节 / 4 字节每元素)
console.log(int32View[0]);     // 100

你也可以直接创建类型化数组,而不显式创建 ArrayBuffer

const uint8 = new Uint8Array([0, 1, 2, 255]);
console.log(uint8.length); // 4
console.log(uint8[3]);     // 255

3. 重要特性

  • 固定长度:创建后长度不可变。
  • 底层共享:多个视图可共享同一 ArrayBuffer,修改一个会影响其他。
    const buf = new ArrayBuffer(4);
    const i32 = new Int32Array(buf);
    const u8  = new Uint8Array(buf);
    i32[0] = 0x12345678;
    console.log(u8); // [0x78, 0x56, 0x34, 0x12] (小端序)
    
  • 字节序:默认使用平台字节序(通常是小端),如需跨平台操作,可用 DataView 指定字节序。

4. 与普通数组的区别

特性 普通数组 (Array) 类型化数组 (TypedArray)
类型 任意类型混合 单一固定数值类型
长度 动态可变 创建后固定
内存布局 非连续(对象引用) 连续(类似 C 数组)
性能 较低(解释器开销) 高(接近原生)
instanceof Array true false
方法 丰富(push, map, filter…) 部分方法(无 push/pop

5. 常见用途

  • WebGL 交互(传递顶点、纹理数据)
  • 音频/视频处理(如 Web Audio API
  • 文件或网络二进制数据处理(如 fetch().arrayBuffer()
  • WebAssembly 内存交换
  • 高性能数值计算(如科学计算、游戏)

6. 注意事项

  • 类型化数组没有 pushpopsplice 等可变方法。
  • 超出范围的值会静默溢出或钳制(如 Uint8Array 中写 300 → 实际存 44)。
  • 不要使用 for...in 遍历(会遍历非索引属性),推荐 for...of 或普通 for
posted @ 2025-12-31 15:06  悠哉大斌  阅读(10)  评论(0)    收藏  举报