跳到主要内容

Typed Array:为什么需要它?ArrayBuffer、视图、DataView 是什么关系?

面试速答(30 秒版 TL;DR)

  • JS 普通数组是“通用容器”,元素类型可以混合,适合业务开发;但它不适合高性能二进制数据处理。
  • Typed Array(类型化数组)是对连续二进制内存的视图,元素类型固定,例如 Int8ArrayUint32ArrayFloat64Array
  • 核心三件套:
    • ArrayBuffer:原始字节缓冲区,本身不能直接读写;
    • TypedArray:按固定类型解释这块内存;
    • DataView:按任意偏移和字节序读写,更灵活。
  • 典型场景:文件处理、网络协议、音视频、Canvas 像素、WebGL、WebAssembly 数据交换。

心智模型:一块内存,多种视角

可以把它理解成:

  • ArrayBuffer 是一块“裸内存”;
  • Uint8Array / Float32Array 这些是“带类型的窗口”;
  • DataView 是“可自定义读写规则的窗口”。

为什么普通数组不够用

普通数组的问题不是“不能存数字”,而是:

  • 元素类型不固定;
  • 内部表示更复杂;
  • 不适合直接映射到底层二进制内存;
  • 和文件、网络包、像素、音频采样这类“字节数据”对接不自然。

Typed Array 的优势:

  • 元素类型固定,便于引擎优化;
  • 内存连续,适合批量处理;
  • 能直接和浏览器底层 API / 二进制协议对接。

三个核心角色

1. ArrayBuffer

ArrayBuffer 只是字节缓冲区:

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

特点:

  • 长度固定;
  • 不能直接 buffer[0] 访问;
  • 必须通过视图来读写。

2. TypedArray

const buffer = new ArrayBuffer(8);
const view = new Uint8Array(buffer);

view[0] = 255;
view[1] = 10;

console.log(view[0]); // 255

常见类型:

类型每个元素字节数说明
Int8Array / Uint8Array18 位整数
Int16Array / Uint16Array216 位整数
Int32Array / Uint32Array432 位整数
Float32Array4单精度浮点
Float64Array8双精度浮点

3. DataView

DataView 更灵活,适合协议解析:

const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);

view.setUint16(0, 256, true); // true 表示 little-endian
console.log(view.getUint16(0, true)); // 256

它的优势是:

  • 可以从任意字节偏移开始读;
  • 可以指定大小端;
  • 适合解析复杂二进制格式。

多个视图共享同一块内存

这是 Typed Array 的一个核心考点。

const buffer = new ArrayBuffer(4);
const bytes = new Uint8Array(buffer);
const words = new Uint16Array(buffer);

bytes[0] = 1;
bytes[1] = 2;

console.log(words[0]); // 结果取决于字节序解释

面试要点:

  • 不同视图可以共享同一个 ArrayBuffer
  • 改一个视图,本质是在改同一块底层内存,其他视图会看到变化。

subarrayslice 的区别

这是很容易被追问的点。

const arr = new Uint8Array([1, 2, 3, 4]);

const a = arr.subarray(1, 3);
const b = arr.slice(1, 3);

a[0] = 99;

console.log(arr[1]); // 99
console.log(b[0]); // 2

结论:

  • subarray() 返回的是共享底层内存的视图
  • slice() 返回的是复制后的新数据

字节序(Endian)怎么答

字节序就是“多字节数据在内存里的存放顺序”:

  • 大端(Big-endian):高位字节放前面;
  • 小端(Little-endian):低位字节放前面。

为什么这题常和 DataView 一起考:

  • TypedArray 一般遵循宿主平台的原生字节序;
  • DataView 可以显式指定 littleEndian 参数,更适合跨平台协议读写。

面试一句话:

  • “只要涉及网络协议、文件格式、跨平台二进制交换,我会优先关注字节序问题,必要时用 DataView 明确控制。”

典型使用场景

1. 处理文件 / Blob / 网络响应

const resp = await fetch("/file.bin");
const buffer = await resp.arrayBuffer();
const bytes = new Uint8Array(buffer);

2. Canvas 像素数据

浏览器中的像素操作经常直接返回字节数组视图。

3. 音视频 / WebGL / WebGPU / WebAssembly

这些场景本质上都偏底层、偏二进制,Typed Array 是天然接口。


高频题标准答法

1. Typed Array 和普通数组有什么区别

普通数组面向业务值集合,类型灵活;Typed Array 面向固定类型的二进制内存视图,强调性能和底层交互。

2. 为什么 ArrayBuffer 不能直接读写

因为它只是原始缓冲区,不带“如何解释字节”的信息,必须通过视图访问。

3. TypedArrayDataView 怎么选

  • 数据结构规则、按固定类型顺序处理时,优先 TypedArray
  • 需要任意偏移、混合类型、控制字节序时,优先 DataView

易错点 / 坑

  • 以为 TypedArray 就是普通数组的高性能版本;它们的定位不同,很多数组方法语义也不同。
  • 忽略 subarray() 共享内存,修改视图时意外影响原数据。
  • 忘记字节序,导致跨平台或协议解析结果错误。
  • 以为 ArrayBuffer 长度能像普通数组一样随便扩容;它是固定长度的。

速记要点(可背诵)

  • ArrayBuffer 是原始字节内存,TypedArray / DataView 是视图。
  • Typed Array 元素类型固定、内存连续,适合二进制和高性能场景。
  • 多个视图可以共享同一块缓冲区。
  • 协议解析和字节序控制,优先考虑 DataView