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详解

相关推荐
xiaofeichaichai1 小时前
Webpack
前端·webpack·node.js
问心无愧05131 小时前
ctf show web入门111
android·前端·笔记
唐某人丶2 小时前
模型越来越强,我们还需要 Agent 工程吗?—— 从价值重估到 Harness 实践
前端·agent·ai编程
智码看视界2 小时前
现代Web开发基础:全栈工程师的起航点
前端·后端·c5全栈
JS菌2 小时前
手写一个 AI Agent 全栈项目:从沙箱执行到子智能体的完整实现
前端·人工智能·后端
excel3 小时前
HLS TS 文件损坏的元凶:Git 提交与拉取
前端
Aphasia3113 小时前
https连接传输流程
前端·面试
徐小夕3 小时前
万字长文!千万级文档 RAG 知识库系统落地实践
前端·算法·github
threelab4 小时前
Three.js 物理模拟着色器 | 三维可视化 / AI 提示词
开发语言·前端·javascript·人工智能·3d·着色器