Typed Array:为什么需要它?ArrayBuffer、视图、DataView 是什么关系?
面试速答(30 秒版 TL;DR)
- JS 普通数组是“通用容器”,元素类型可以混合,适合业务开发;但它不适合高性能二进制数据处理。
- Typed Array(类型化数组)是对连续二进制内存的视图,元素类型固定,例如
Int8Array、Uint32Array、Float64Array。 - 核心三件套:
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 / Uint8Array | 1 | 8 位整数 |
Int16Array / Uint16Array | 2 | 16 位整数 |
Int32Array / Uint32Array | 4 | 32 位整数 |
Float32Array | 4 | 单精度浮点 |
Float64Array | 8 | 双精度浮点 |
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。 - 改一个视图,本质是在改同一块底层内存,其他视图会看到变化。
subarray 和 slice 的区别
这是很容易被追问的点。
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. TypedArray 和 DataView 怎么选
- 数据结构规则、按固定类型顺序处理时,优先
TypedArray; - 需要任意偏移、混合类型、控制字节序时,优先
DataView。
易错点 / 坑
- 以为
TypedArray就是普通数组的高性能版本;它们的定位不同,很多数组方法语义也不同。 - 忽略
subarray()共享内存,修改视图时意外影响原数据。 - 忘记字节序,导致跨平台或协议解析结果错误。
- 以为
ArrayBuffer长度能像普通数组一样随便扩容;它是固定长度的。
速记要点(可背诵)
ArrayBuffer是原始字节内存,TypedArray/DataView是视图。- Typed Array 元素类型固定、内存连续,适合二进制和高性能场景。
- 多个视图可以共享同一块缓冲区。
- 协议解析和字节序控制,优先考虑
DataView。