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

相关推荐
Bigger1 小时前
😮‍💨 有了 AI 之后,我怎么感觉反而更累了?
前端·aigc·ai编程
Dxy12393102161 小时前
HTML中使用Canvas动态图形渲染:解锁Web交互新维度
前端·html·图形渲染
西陵1 小时前
如何实现 Claude 生成式 UI?一套可落地的工程方案
前端·人工智能·ai编程
FlyWIHTSKY1 小时前
Vue 3 + 原生 CSS Float
前端·css·vue.js
energy_DT1 小时前
2026海上钻井平台可视化运维:红外热成像、超声波、AI视频巡检、数字孪生
前端
ONLYOFFICE1 小时前
如何将 Word 集成到 Web 应用程序? 5 种方法详解与对比
前端·word·onlyoffice
533_1 小时前
[pinia] vue3中监听pinia值的变化
前端·javascript·vue.js
一叶飘零晋1 小时前
【(二)Electron 使用之常用技巧】
javascript·electron·ecmascript
漫游的渔夫1 小时前
前端开发者做 Agent:Tool Calling 别只写函数名,用 Schema 少踩 5 个坑
前端·人工智能·typescript