Map天然按插入顺序遍历,因内部用有序链表+哈希表实现,键不转字符串、区分类型,ES规范强制保证顺序,与对象的枚举规则(整数键优先)有本质区别。

JS 中的 Map 通过内部维护一个插入时的链表(或类似有序结构)来存储键值对,天然保证遍历时按插入顺序返回,不需要额外排序或干预。
Map 存储键值对的方式
Map 使用 set(key, value) 方法添加键值对。它不把键强制转为字符串,而是直接用原始值作为键的标识——哪怕键是对象、函数、NaN 或 Symbol,Map 都能区分并正确存储。
- 每个键在内部被独立哈希或引用,不会发生类型转换(比如
{}和{}是两个不同键) - 重复调用
set()同一个键,会覆盖旧值,不改变位置 - 底层实现上,主流引擎(V8、SpiderMonkey 等)用有序链表 + 哈希表组合,兼顾查找效率与顺序保证
插入顺序是如何保持的
Map 的迭代器(keys()、values()、entries()、for...of)始终从第一个插入的键值对开始,逐个向后访问,和你调用 set() 的先后完全一致。
- 即使键是数字
1、5、z、@,也不会像普通对象那样把数字键提前 - 删除某个键(
delete())后,后续键的顺序不变;新插入的键总追加到末尾 - 这个行为是 ES 规范强制要求的,所有合规引擎都必须遵守,不存在跨浏览器差异
和普通对象对比的关键区别
普通对象的属性枚举顺序受键类型影响:整数索引键(如 "1"、"5")会被优先升序排列,其余字符串键才按插入顺序,Symbol 键排最后。而 Map 完全无视键类型,只认插入时间。
- 对象:
{ z: 1, '@': 2, b: 3, 1: 4, 5: 5 }→ 枚举顺序可能是1、5、z、@、b - Map:
map.set('z',1).set('@',2).set('b',3).set(1,4).set(5,5)→ 遍历一定按'z'、'@'、'b'、1、5的顺序
实际使用中的注意事项
保持顺序不是“自动生效”的魔法,而是依赖你正确使用 Map 的 API。一旦混用对象操作,就可能破坏预期。
- 避免用
Object.assign({}, map)或展开运算符{...map}转成对象——这会丢失顺序且键被转成字符串 - 想转成数组结构,用
Array.from(map)或[...map],它们返回[[key, value], ...]形式,保留原始顺序 - 初始化时可用可迭代对象:
new Map([['a', 1], ['b', 2]]),顺序由数组元素位置决定


















