前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库类型化数组与普通数组 内存表示差异
JavaScript数据处理

Uint8Array 和普通数组有什么区别?

普通数组是一个能随便放东西、随时变长的集合;Uint8Array 是一块固定大小的二进制内存(ArrayBuffer)上的「读取方式」,长度和元素类型在创建时就定死了,只能存数字,超出范围的值会被截断,也没有 push 和 pop 这类方法。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#数据处理
先看核心答案读代码示例
理解线索

一段内存,多种读法

  1. ArrayBuffer一段固定长度的原始字节,自己不能读写,只有 byteLength
  2. 类型化数组Uint8Array 或 Float32Array 这类,按固定类型和宽度解释这段字节
  3. 普通数组长度可变、元素类型任意,内存怎么排由引擎决定

多字节视图(如 Uint16Array)按当前机器的字节序读数据,常见设备都是小端。解析网络协议或文件格式时要用 DataView 显式指定字节序。

核心回答

先记住这个答案

Uint8Array 不是一种「更快的数组」,而是一块二进制内存的视图。底下是一个 ArrayBuffer,也就是一段固定长度的原始字节;Uint8Array 规定了怎么读它:每个元素 1 个字节、无符号整数。所以它长度固定、没有 push 和 pop,只能存数字,写入超出 0 到 255 的值会被转换。普通数组则可以随时变长、什么值都能放,内存怎么排由引擎自己优化,不承诺连续。

  • ArrayBuffer 是一段字节,Uint8Array 是看这段字节的方式
  • 长度固定,没有 push 这类改变长度的方法
  • 写入超出范围的值会被转换,Uint8Array 里 300 变成 44
  • 多个视图可以共享同一个 ArrayBuffer

同一块内存,两种读法

最能说明「视图」这个概念的,是在同一个 ArrayBuffer 上建两个不同类型的数组。

Uint8Array 和 Uint16Array 看同一段字节JavaScript
const buffer = new ArrayBuffer(4)       // 4 个字节
const bytes = new Uint8Array(buffer)    // 每 1 字节一个元素
const words = new Uint16Array(buffer)   // 每 2 字节一个元素

bytes[0] = 0xff
bytes[1] = 0x01

console.log(bytes.length, words.length) // 同一块内存,元素个数不同
console.log(words[0])                   // 前两个字节合起来读
console.log(typeof bytes.push)          // 没有 push
查看输出与解释
4 2
511
undefined

4 个字节,按 1 字节一个元素读是 4 个,按 2 字节一个元素读是 2 个。改的是 bytes,但 words 立刻就能看到,因为它们底下是同一段内存,视图本身不存数据。 words[0] 是 511,也就是 0x01ff。前两个字节依次是 0xff 和 0x01,小端机器把低位放在前面,所以读成 0x01ff。如果机器是大端,读出来就是 0xff01。这就是为什么解析网络协议时不直接用 Uint16Array,而是用 DataView 的 getUint16(offset, littleEndian),把字节序写死。

长度和类型都是定死的

普通数组的习惯用法在类型化数组上很多都不成立。

越界和超范围写入
Uint8Array 写入 300,会按 256 取模变成 44;写入 -1 变成 255。Int8Array 写 200 会变成 -56。普通数组写 300 就是 300。 越界写入也不一样。普通数组 arr[10] = 1 会把长度撑到 11;类型化数组 bytes[10] = 1 什么都不发生,bytes.length 还是 4,bytes[10] 读出来是 undefined。它不会报错,所以写错下标很难发现。
为什么要这么设计
类型固定、内存连续,引擎就能把它直接交给底层用:WebGL 的顶点数据、Web Audio 的采样、fetch 读到的二进制、FileReader 读出的文件内容,都是一段字节。普通数组每个元素可能是任意类型,要先转换一遍才能交出去。所以处理图片、音视频、二进制协议时用类型化数组,普通业务数据还是用普通数组。
回答前,多想一步

容易答错的地方

以为 Uint8Array 是数组
Array.isArray(bytes) 是 false。它有 map 和 filter 这类方法,但改变长度的方法一个都没有。JSON.stringify(new Uint8Array([1, 2])) 得到的是 {"0":1,"1":2},而不是 [1,2],要先 Array.from 转一下。
以为 map 能返回普通数组
类型化数组的 map 返回的还是同类型的类型化数组。new Uint8Array([200, 100]).map(x => x * 2) 结果是 [144, 200],400 被截断成了 144。要保留原值得先转成普通数组再 map。
以为视图总是覆盖整个 ArrayBuffer
new Uint8Array(buffer, 1, 2) 只看下标 1 和 2 这两个字节。把它的 .buffer 传给别的 API,对方拿到的是完整的 4 个字节,可能把不该给的数据也带出去了。要传就传视图本身,或者先 slice 复制一份。
试着用自己的话回答

面试官还会怎么问?

Uint8ClampedArray 和 Uint8Array 有什么区别?

超范围时的处理不同。Uint8Array 取模,300 变成 44;Uint8ClampedArray 夹紧,300 变成 255,-1 变成 0。Canvas 的 getImageData 返回的像素数据就是 Uint8ClampedArray,因为颜色值调亮过头应该是最亮,而不是绕回到很暗。

视图能从任意字节位置开始吗?

不能。byteOffset 必须是元素宽度的整数倍,new Uint16Array(buffer, 1) 会抛 RangeError,因为 2 字节的元素要从偶数位置开始。DataView 没有这个限制,可以从任意位置读多字节的值,这也是解析二进制格式常用它的原因。

类型化数组能传给 Worker 吗?

能,默认会被复制一份。如果数据很大,可以把 buffer 放进 postMessage 的转移列表里,所有权直接转给 Worker,不复制。转移之后原来那边的 buffer 就被分离了,byteLength 变成 0,原视图也读不到数据了。

从一道题,走向一组知识

把知识连起来

数据处理

类型化数组的 subarray 和 slice 有什么区别?

视图共享内存这一点,在 subarray 和 slice 的区别上体现得最直接。

数据处理

正则加不加 u 标志,匹配 emoji 时有什么区别?

字符串内部也是按 16 位单元存的,和 Uint16Array 一样,emoji 要占两个单元。

参考资料

  • JavaScript:数据处理参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 同一块内存,两种读法
  3. 长度和类型都是定死的
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑