JavaScript 数组不是数组,是对象

一、先说结论:JS 数组不是"数组"

C 语言的数组是连续内存块,每个元素占据固定大小,通过指针偏移访问。JS 的数组从底层看就是一个对象------key 是数字字符串,value 是任意类型。

javascript 复制代码
const arr = ['a', 'b', 'c'];
// 本质上等价于:
const obj = { '0': 'a', '1': 'b', '2': 'c', length: 3 };

这就是 JS 数组可以存放不同类型元素、可以稀疏(有空洞)的根因------它本来就不是连续内存。


二、V8 的优化:快数组和慢数组

虽然 JS 规范说数组是对象,但 V8 引擎做了大量优化。

当数组是"紧凑"的(没有空洞,元素类型一致)时,V8 使用 快数组(Fast Elements)------一段连续的内存,用 offset 直接访问,和 C 数组一样快。

当数组出现以下情况时,V8 会降级为 慢数组(Dictionary Elements)

  • 出现空洞(arr[100] = 1 而前面大部分为空)
  • 元素类型不一致且经常变化
  • 删除中间元素

慢数组用哈希表存储,访问速度下降,但节省了内存(不需要为空洞分配空间)。


三、length 不是只读的

JS 数组的 length 属性可以被显式赋值。把 length 设小会截断数组,设大会产生空洞:

javascript 复制代码
const arr = [1, 2, 3, 4, 5];
arr.length = 3;
console.log(arr); // [1, 2, 3]

arr.length = 5;
console.log(arr[4]); // undefined(空洞)

这个行为在其他语言中是不存在的,但在 JS 中是规范定义------因为 length 本质上是对象的一个属性。


四、forEach 和 map 跳过空洞

javascript 复制代码
const arr = [1, , , 4];
arr.forEach(x => console.log(x)); // 1, 4(跳过空洞)
console.log(arr.map(x => x * 2)); // [2, empty × 2, 8]

这是 JS 数组的一个常见的坑:空洞不会被遍历方法处理。而 for (let i = 0; i < arr.length; i++) 会返回 undefined。


五、理解这个对写代码有什么帮助

  1. 避免稀疏数组new Array(1000).fill(0)new Array(1000) 后面遍历赋值快得多------fill 让 V8 保持快数组模式
  2. 预分配性能更好 :如果你知道数组大小,const arr = new Array(n) 可以让 V8 提前分配空间
  3. delete arr[i] 不如 splice:delete 创建空洞(变成慢数组),splice 保持紧凑
  4. 类型一致更快[1,2,3][1,'a',true] 快,因为 V8 可以做更多类型特化

六、总结

  1. JS 数组底层是对象,key 是数字字符串,value 任意
  2. V8 用快数组(连续内存)优化紧凑数组,遇到空洞降级为慢数组(哈希表)
  3. length 可写、forEach 跳过空洞、delete 产生空洞------这些行为都能用"数组本质是对象"来解释
  4. 理解底层实现有助于写出性能更好的代码
相关推荐
专业抄代码选手4 小时前
08|Fiber 上的 `useState`:状态终于属于具体组件
前端·javascript·react.js
默_笙4 小时前
😭 Vibe Coding 翻车实录:AI 编程为什么必须先写"剧本"
前端·javascript
lerhxx5 小时前
我用 R3F 手搓了一个能走进去的 3D 迷宫简历(上):从选型架构到迷宫生成算法
前端·javascript·three.js
鹏多多10 小时前
PC 网站接入微信登录,这 10 个坑我替你踩完了!
前端·javascript·vue.js
用户2986985301411 小时前
React 中 HTML 内容转 Word 文档的实现方案
javascript·react.js·html
mONESY11 小时前
我用 Next.js 16 + Supabase 从零做了个「背单词」H5 应用
javascript
boooooooom11 小时前
手把手做一个图 RAG 烹饪问答系统:Neo4j + Milvus + LLM 的工程实践
前端·javascript·后端
染指111014 小时前
103.RAG-LLamaIndex后端rag问答-聊天接口
前端·javascript·vue.js·人工智能
单线程_011 天前
从案例分析 Vue3 Tokenizer+Parser 源码三
前端·javascript·vue.js
小磊哥er1 天前
深入解构Claude Code - 第 8 篇 · 数据放哪、钱怎么算
javascript·ai编程