Web前端之JavaScrip中的Array、Object、Map和Set详解


一、四种结构的"真实身份"

结构 你以为 引擎里其实是 核心用途
Array 列表 连续内存 + 索引 顺序访问
Object 键值对 字符串键哈希表(有退化路径) 配置/字典
Map 键值对 真正的通用哈希表 高频查找
Set 集合 只有 key 的哈希表 极快存在判断

二、为什么 Object 在大量 key 下会变慢?

很多人不知道:Object 不是一直都是哈希表。
在 V8 里,Object 有两种形态:
1、少量固定 key 时 ------ Hidden Class(快)
像这样:const o = { a: 1, b: 2 };
引擎会创建隐藏类(Hidden Class),属性访问变成:类似 C 结构体的偏移量访问(极快)
2、key 变多 / 动态增删时 ------ 退化为字典模式(慢)
for (let i = 0; i < 100000; i++) { o['k' + i] = i; }
此时:Object 会退化为 Dictionary Mode(哈希 + 链表),性能明显下降,内存也暴涨。


三、为什么 Map 永远稳定快?

const m = new Map();
Map 从设计开始就是:纯哈希表结构,没有 Hidden Class、没有退化路径
特性:
1、任意类型 key
2、不会退化
3、专为高频查找设计
4、内存布局为桶 + 链/开放寻址
所以当 key 很多时:Object <<<< Map差距非常明显。


四、为什么 Set 遍历反而比 Array 慢?

很多人踩这个坑:for (const x of set) {}for (const x of arr) {}慢很多。
原因:

Array Set
连续内存 哈希桶跳跃
CPU cache 友好 cache miss 严重
指针少 指针多

Set 每次遍历是:桶 → 指针 → 元素 → 下一个桶 → 指针...
这是CPU 最讨厌的访问模式。
所以:Set 快在查找,不快在遍历。


五、真正的内存结构示意

Array(极度友好)
[1][2][3][4][5]
一整块连续内存。


Set / Map(典型哈希桶)

javascript 复制代码
bucket[0] → node → node
bucket[1]
bucket[2] → node
bucket[3] → node → node → node

大量指针跳转。


六、为什么很多人代码慢却不知道原因?

典型误用

javascript 复制代码
const set = new Set(bigList);

for (const x of set) { ... }  // ×

等于用"查找结构"干"遍历结构"的活。


正确模式

javascript 复制代码
const set = new Set(bigList);

for (const x of otherBigList) {
  if (set.has(x)) { ... }   // √
}

七、终极理解(非常关键)

需求 正确结构
频繁遍历 Array
频繁存在判断 Set
大量 key 查值 Map
少量固定字段 Object

这不是语法选择。
是数据结构选择。


八、一句话升维总结

1、Array 是内存结构
2、Set / Map 是索引结构
3、Object 是语法糖结构(会退化)


九、为什么 for (let i=0; i<arr.length; i++) 仍然是 JS 里最快的循环,没有之一

1、先给结论(很重要)

在 V8 里:经典 for 循环之所以最快,本质是最容易被 JIT 编译成"纯机器码循环"


2、V8 是怎么执行 JS 循环的?

JS 代码不会直接执行,而是:
1、解释执行(Ignition)
2、热点代码 JIT 编译(TurboFan)
3、生成优化机器码
for 循环为什么容易被优化?
看这个:

javascript 复制代码
for (let i = 0; i < arr.length; i++) {
  sum += arr[i];
}

V8 可以"确定"几件事:
1、i 是纯数字递增
没有类型变化
2、arr 是连续结构(大概率)
可当成 连续内存数组
3、length 是稳定值
可以 hoist(提取到循环外)
优化后变成类似:

javascript 复制代码
for (int i = 0; i < len; i++) {
    sum += memory_base[i];
}

这已经接近 C 代码了


3、为什么 forEach 更慢?

javascript 复制代码
arr.forEach(x => sum += x);

问题
1、回调函数调用成本
每次循环:函数调用栈 + 参数绑定 + 作用域处理
2、无法 inline(内联优化困难)
JIT 很难把x => sum += x完全折叠进循环里
3、控制流不可预测
return / break / throw 语义复杂


4、为什么 for...of 也不如 for?

javascript 复制代码
for (const x of arr)

问题
1、需要 iterator 协议
底层是arr[Symbol.iterator]()
2、每次 next() 调用
iterator.next()多一层抽象
3、无法完全消除边界检查


5、关键对比(非常重要)

写法 V8 优化等级 真实执行
for (i++) ⭐⭐⭐⭐⭐ 机器码循环
while ⭐⭐⭐⭐ 接近机器码
forEach ⭐⭐ 函数调用循环
for...of ⭐⭐ iterator循环

6、真正的性能核心:不是语法,是"可预测性"

V8 最喜欢的代码特征
类型稳定 → i = number
结构稳定 → arr = packed array
无抽象层 → 没有 callback / iterator
可线性访问 → 连续内存


7、隐藏关键点:数组在 V8 里的真实形态

数组不是"数组",而是:Elements Kind(元素类型系统)

类型 名字 性能
SMI_ELEMENTS 小整数数组 最快
DOUBLE_ELEMENTS 浮点数组
OBJECT_ELEMENTS 混合类型

一旦这样做:arr.push("string");
数组直接退化:SMI → OBJECT_ELEMENTS
性能下降一个档次


8、为什么 for 是"终极循环形态"?

1、没有函数调
2、没有 iterator
3、没有 closure 捕获
4、没有协议层
5、可以完全编译成 CPU 指令循环


9、一句话终极本质

for 循环之所以最快,不是因为语法简单
而是因为它最接近 CPU 的真实执行模型


十、CPU + 编译器级别

ChatGPT详解

相关推荐
এ慕ོ冬℘゜1 小时前
前端实战:jQuery实现动态表格渲染与状态切换功能
前端·javascript·jquery
zzzzzz3101 小时前
react-bits:把酷炫动效从“灵感截图”变成可复用的 React 组件
javascript·react.js·动效
jay神2 小时前
【计算机毕业设计】基于Flask+Vue的电影数据可视化与智能推荐系统
前端·vue.js·python·信息可视化·flask·毕业设计·课程设计
FreeTinker8 小时前
HTML本地存储技术解析:localStorage与sessionStorage的原理、差异与应用场景
前端·html
qq_452396238 小时前
第十二篇:《全链路监控与可观测性:前端错误追踪与性能分析》
前端
海兰9 小时前
【应用】基于 Next.js 16 + Python mplfinance的金融K线图与技术指标可视化平台(三)
javascript·python·金融
wangruofeng9 小时前
Phosphor Icons 官网源码拆解:URL 即存储、水波动画与 7362 Star 图标库的架构实践
前端·架构·github
BigTopOne9 小时前
WebRTC Native / Android 开发学习资源整理
前端
excel10 小时前
nuxt 3 升级 nuxt 4 报错之 hasInjectionContext
前端
小磊哥er10 小时前
深入解构Claude Code - 第 7 篇 · 连接外面的世界
javascript·ai编程