前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 热点
旧版
首页程序员面试题库类型化数组 subarray 与 slice 区别
JavaScript数据处理

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

subarray 不复制数据,只是在原来那块内存上开一个新窗口,改它原数组也跟着变。slice 会把选中的元素复制到一块新内存里,之后两边互不影响。要临时看一段数据用 subarray,要把数据存下来或交给别人用 slice。

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

开窗口还是拷一份

  1. subarray同一个 buffer,只改了起始偏移和长度,创建几乎不花时间
  2. slice新建一个 ArrayBuffer,把选中范围的元素复制进去
  3. 所有权数据会被后续写入覆盖时,交出去之前必须复制

普通数组的 slice 就是复制,很多人顺手以为类型化数组的 subarray 也是复制,把它存起来之后才发现内容变了。

核心回答

先记住这个答案

两个方法的参数一样,都是 (begin, end),不包含 end,但返回的东西性质不同。subarray 返回一个新视图,和原数组共用同一个 ArrayBuffer,只是起点和长度不一样,所以创建很快,但改它就是改原数组。slice 会新建一个 ArrayBuffer,把选中范围复制过去,得到的是独立的副本。判断用哪个,就看这段数据之后会不会被别人改掉。

  • subarray 共享内存,改一边另一边也变
  • slice 复制到新的 ArrayBuffer,两边独立
  • subarray 是 O(1),而 slice 是 O(n)
  • 两者参数都是元素下标,不是字节偏移

改一个,另一个变不变

从同一个数组里用两种方法各取前两个元素,然后分别修改结果。

对比共享和复制JavaScript
const source = Uint8Array.from([10, 20, 30, 40])
const shared = source.subarray(0, 2) // 共享内存的视图
const copied = source.slice(0, 2)    // 独立的副本

shared[0] = 99 // 会改到 source
copied[1] = 88 // 不影响 source

console.log(source.join(','))
console.log(shared.join(','), copied.join(','))
console.log(shared.buffer === source.buffer, copied.buffer === source.buffer)
查看输出与解释
99,20,30,40
99,20 10,88
true false

shared[0] = 99 直接写进了 source 的第一个字节,因为两者底下是同一块内存。copied 是复制时的快照,之后怎么改都和 source 无关。最后一行比较 .buffer,能直接看出谁和原数组共用内存。 代价也就清楚了。subarray 只是创建一个小对象记录偏移和长度,和数据量无关,是 O(1)。slice 要分配内存并逐个复制,是 O(n),数据越大越慢。

复用缓冲区时 subarray 的坑

处理二进制数据时,为了少分配内存,常见做法是准备一个固定的缓冲区反复读写。比如解析网络包,每次都把新数据写进同一个 Uint8Array。

存下来的数据被下一次写入覆盖
假设每读到一个包,就用 subarray 取出包体交给一个异步任务处理。任务还没来得及跑,下一个包已经写进了同一块缓冲区。这时任务拿到的视图指向的内存早就变成了新包的内容,处理的是错的数据,也不会报任何错。 修法是交出去之前 slice 一份。原则很简单:数据只在当前这一轮同步代码里用,用 subarray 省一次复制;要存起来、要跨过 await、要交给别的模块,用 slice。
参数是元素下标,不是字节
对 Uint32Array 调 subarray(1),新视图的 byteOffset 是 4,因为跳过了一个 4 字节的元素。协议文档里写的往往是字节偏移,这时要么先除以元素宽度,要么直接用 Uint8Array 或 DataView 按字节操作。
回答前,多想一步

容易答错的地方

以为 subarray 和普通数组的 slice 一样
普通数组的 slice 是浅复制。类型化数组里只有 slice 是复制,subarray 从名字上看像「取子数组」,其实是共享视图,这是最常见的误解。
以为 subarray 能省内存
它确实不复制,但只要这个小视图还被引用着,整个底层 ArrayBuffer 都不能被回收。从一个 10MB 的缓冲区里 subarray 出 10 个字节长期保存,占着的是 10MB。这种情况反而应该 slice 出来,让大缓冲区能被释放。
以为 .buffer 相同就代表数据重叠
两个视图 .buffer 相同,只说明在同一块内存上,不代表它们看的区间有交集。要判断会不会互相影响,还得比较 byteOffset 和 byteLength 算出的范围。
试着用自己的话回答

面试官还会怎么问?

subarray 支持负数下标吗?

支持,和数组的 slice 规则一样,负数从末尾往前算。Uint8Array.from([10, 20, 30, 40]).subarray(-2) 得到 [30, 40],它的 byteOffset 是 2。超出范围的下标会被夹到有效范围内,不会报错。

ArrayBuffer 自己的 slice 是复制还是共享?

复制。buffer.slice(begin, end) 按字节范围返回一个新的 ArrayBuffer。ArrayBuffer 没有 subarray,想共享就在它上面新建一个带偏移的视图,比如 new Uint8Array(buffer, 4, 8)。

TextDecoder 解码时传 subarray 会有问题吗?

不会,decode 只读视图覆盖的那一段字节,传 bytes.subarray(0, n) 是解码缓冲区里有效部分的常见写法,而且省掉了一次复制。

从一道题,走向一组知识

把知识连起来

数据处理

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

都是在处理「一段数据被切在哪里」,字符串切在代理对中间会得到半个 emoji。

数据处理

两个看起来一样的 é,为什么用 === 比较是 false?

同样是字节或字符层面的比较问题,两段看着一样的字符串,底层可能是不同的码点序列。

参考资料

  • JavaScript:数据处理参考资料

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

本题目录
  1. 先记住这个答案
  2. 改一个,另一个变不变
  3. 复用缓冲区时 subarray 的坑
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

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

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