TypedArray 详解

TypedArray 详解

一、什么是 TypedArray

TypedArray 是 JavaScript 中处理二进制数据的对象,它提供了类似数组的视图来访问原始二进制缓冲区中的数据。

核心特点:

  • 类型化:每个元素都有固定的数据类型(如 Int8、Uint32、Float64 等)

  • 高性能:直接操作内存,避免了 JavaScript 对象的开销

  • 固定长度:创建后长度不可变

  • 内存高效:数据在内存中连续存储

二、TypedArray 类型

类型 字节长度 数值范围 描述
Int8Array 1 -128 ~ 127 8位有符号整数
Uint8Array 1 0 ~ 255 8位无符号整数
Uint8ClampedArray 1 0 ~ 255 8位无符号整数(限制范围)
Int16Array 2 -32768 ~ 32767 16位有符号整数
Uint16Array 2 0 ~ 65535 16位无符号整数
Int32Array 4 -2³¹ ~ 2³¹-1 32位有符号整数
Uint32Array 4 0 ~ 2³²-1 32位无符号整数
Float32Array 4 ±1.2×10⁻³⁸ ~ ±3.4×10³⁸ 32位浮点数
Float64Array 8 ±5.0×10⁻³²⁴ ~ ±1.8×10³⁰⁸ 64位浮点数
BigInt64Array 8 -2⁶³ ~ 2⁶³-1 64位有符号大整数
BigUint64Array 8 0 ~ 2⁶⁴-1 64位无符号大整数

三、基本使用

1. 创建 TypedArray

javascript

复制

下载

复制代码
// 方式1:指定长度(元素个数)
const int8 = new Int8Array(10);  // 10个8位整数
const float32 = new Float32Array(100);  // 100个32位浮点数

// 方式2:从普通数组创建
const arr = [1, 2, 3, 4, 5];
const int16 = new Int16Array(arr);  // [1, 2, 3, 4, 5]

// 方式3:从 ArrayBuffer 创建
const buffer = new ArrayBuffer(16);  // 16字节的缓冲区
const int32 = new Int32Array(buffer);  // 4个32位整数(4×4=16字节)
const uint8 = new Uint8Array(buffer);  // 16个8位整数

// 方式4:从其他 TypedArray 创建
const source = new Float64Array([1.1, 2.2, 3.3]);
const copy = new Float32Array(source);  // 类型转换

2. 基本操作

javascript

复制代码
const float64 = new Float64Array(5);

// 赋值和访问
float64[0] = 3.14;
float64[1] = 2.718;
console.log(float64[0]);  // 3.14

// 长度属性
console.log(float64.length);    // 5(元素个数)
console.log(float64.byteLength); // 40(字节数:5×8字节)
console.log(float64.BYTES_PER_ELEMENT);  // 8(每个元素的字节数)

// 迭代
for (let value of float64) {
    console.log(value);
}

// 使用数组方法(大部分Array方法可用)
float64.fill(0);  // 填充为0
const mapped = float64.map(x => x * 2);
const sum = float64.reduce((a, b) => a + b, 0);

四、性能优势

1. 排序性能对比

javascript

复制代码
// 准备测试数据
const size = 1000000;
const normalArray = new Array(size).fill().map(() => Math.random());
const typedArray = new Float64Array(normalArray);

// 测试原生数组排序
console.time('Array sort');
const sortedNormal = [...normalArray].sort((a, b) => a - b);
console.timeEnd('Array sort');  // ~400-500ms

// 测试 TypedArray 排序
console.time('TypedArray sort');
const sortedTyped = typedArray.slice().sort();
console.timeEnd('TypedArray sort');  // ~50-80ms(快5-10倍!)

2. 数值计算性能

javascript

复制代码
// 矩阵乘法示例
function matrixMultiply(A, B, size) {
    const C = new Float64Array(size * size);
    
    for (let i = 0; i < size; i++) {
        for (let k = 0; k < size; k++) {
            const aik = A[i * size + k];
            for (let j = 0; j < size; j++) {
                C[i * size + j] += aik * B[k * size + j];
            }
        }
    }
    return C;
}

// 使用 TypedArray 比普通数组快 2-3 倍

五、实际应用场景

1. WebGL / 图形处理

javascript

复制代码
// 顶点缓冲区
const vertices = new Float32Array([
    // x, y, z
    -1.0, -1.0,  0.0,
     1.0, -1.0,  0.0,
     0.0,  1.0,  0.0
]);

// 颜色缓冲区
const colors = new Uint8Array([
    // r, g, b, a
    255, 0, 0, 255,
    0, 255, 0, 255,
    0, 0, 255, 255
]);

// 传递给 WebGL
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

2. 音频处理

javascript

复制代码
// 音频缓冲区
const audioContext = new AudioContext();
const sampleRate = 44100;
const duration = 2;  // 2秒
const frameCount = sampleRate * duration;

// 创建音频数据
const audioBuffer = audioContext.createBuffer(
    1,  // 单声道
    frameCount,
    sampleRate
);

// 获取 TypedArray 进行数据处理
const channelData = audioBuffer.getChannelData(0);  // Float32Array

// 生成正弦波
for (let i = 0; i < frameCount; i++) {
    const time = i / sampleRate;
    channelData[i] = Math.sin(2 * Math.PI * 440 * time);  // 440Hz A音
}

3. 图像处理

javascript

复制代码
// 处理 Canvas 图像数据
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

// data 是 Uint8ClampedArray
const data = imageData.data;  // RGBA 格式

// 灰度化处理
for (let i = 0; i < data.length; i += 4) {
    const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
    data[i] = data[i + 1] = data[i + 2] = avg;
}

ctx.putImageData(imageData, 0, 0);

4. 网络通信 / 文件处理

javascript

复制代码
// 从文件读取二进制数据
async function readFileAsTypedArray(file) {
    const arrayBuffer = await file.arrayBuffer();
    return new Uint8Array(arrayBuffer);
}

// WebSocket 二进制数据传输
const socket = new WebSocket('ws://example.com');
socket.binaryType = 'arraybuffer';

socket.onmessage = function(event) {
    const data = new Float32Array(event.data);
    // 处理二进制数据...
};

六、高级特性

1. 共享内存的 DataView

javascript

复制代码
const buffer = new ArrayBuffer(16);

// 使用 DataView 读写不同字节序的数据
const view = new DataView(buffer);

// 以小端序写入32位整数
view.setInt32(0, 0x12345678, true);  // true 表示小端序

// 以大端序读取
const value = view.getInt32(0, false);  // false 表示大端序

2. 多个视图共享同一缓冲区

javascript

复制代码
const buffer = new ArrayBuffer(16);

// 创建不同视图操作同一内存
const int32View = new Int32Array(buffer);
const uint8View = new Uint8Array(buffer);

int32View[0] = 0x12345678;

console.log(uint8View[0].toString(16));  // 78(小端序最低字节)
console.log(uint8View[1].toString(16));  // 56
console.log(uint8View[2].toString(16));  // 34
console.log(uint8View[3].toString(16));  // 12

3. 与 Web Workers 共享内存

javascript

复制代码
// 主线程
const sharedBuffer = new SharedArrayBuffer(1024 * 1024);  // 1MB 共享内存
const sharedArray = new Int32Array(sharedBuffer);

// 传递给 Worker
worker.postMessage({ buffer: sharedBuffer });

// Worker 线程中可以直接操作同一内存

七、注意事项

1. 类型限制

javascript

复制代码
const uint8 = new Uint8Array([255]);
uint8[0] = 256;  // 溢出!实际存储 0
console.log(uint8[0]);  // 0

// Uint8ClampedArray 会限制在 0-255
const clamped = new Uint8ClampedArray([255]);
clamped[0] = 300;  // 被限制为 255
console.log(clamped[0]);  // 255

2. 长度不可变

javascript

复制代码
const arr = new Int32Array(3);
arr.push(4);  // ❌ 错误!TypedArray 没有 push 方法
arr.length = 5;  // ❌ 无效,长度不会改变

// 只能创建新的
const newArr = new Int32Array([...arr, 4]);

3. 兼容性

  • 所有现代浏览器都支持

  • Node.js 完全支持

  • IE 10+ 部分支持

八、总结

TypedArray 的主要优势:

  1. 性能极高 - 直接内存操作,无 GC 压力

  2. 内存高效 - 紧凑存储,无对象开销

  3. 类型安全 - 明确的数据类型

  4. 硬件加速 - 某些操作可使用 SIMD 指令

适用场景:

  • 大规模数值计算

  • 图形/音频处理

  • 网络协议解析

  • 文件格式处理

  • 需要高性能排序时

不适用场景:

  • 需要动态改变长度的数组

  • 混合类型数据存储

  • 简单的数据操作(普通数组更简单)