Map是键可为任意类型的有序键值对容器,Set是基于SameValueZero算法的去重值集合;二者均不支持JSON.stringify直接序列化,需转为数组处理,且在高频操作中提供稳定O(1)性能。
Map 本质是「键可为任意类型」的键值对容器,而 Object 的键只能是字符串或 Symbol(即使你写 {1: 'a'},实际键也是字符串 "1")。这导致用对象模拟映射时容易出错:obj[{}] === obj[{}] 总是 true(因为两个空对象都转成 "[object Object]"),但 map.set({}, 'a') !== map.set({}, 'b') 是完全独立的条目。
实操建议:
Map,Object 无解Map 保持插入顺序,遍历时按添加顺序返回;Object 的属性顺序在 ES2015 后虽也保证,但仅限字符串/Symbol 键,且原型链上的可枚举属性会干扰 for...in
map.size 是 O(1),Object.keys(obj).length 是 O(n)Set 存储唯一值,内部用 SameValueZero 算法判断重复(即 NaN === NaN 为真),而数组靠手动 filter((v, i, a) => a.indexOf(v) === i) 或 [...new Set(arr)] 去重——后者才是 Set 的典型用途。
常见错误现象:
new Set([{a:1}, {a:1}]) 只存一个对象 → 实际存两个,因对象引用不同arr.includes(item) 在大数组里频繁查找 → 时间复杂度 O(n),换成 set.has(item) 是 O(1)Set 不能通过索引访问元素(没有 set[0]),必须用迭代器或转为数组直接 JSON.stringify(new Map([['a', 1]])) 得到 "{}",JSON.stringify(new Set([1,2])) 也是 "{}"。这是因为它们没有可枚举的自有属性,JSON.stringify 只处理 plain object 的键值对和 array 的索引项。
正确导出方式:
JSON.stringify([...myMap]) // [["a",1],["b",2]]
JSON.stringify([...mySet]) // [1,2,3]
new Map(JSON.parse(str)) 不行,得 new Map(JSON.parse(str)) 改成 new Map(JSON.parse(str)) → 实际应写 new Map(JSON.parse(str))?不对,要解构:const arr = JSON.parse(str); new Map(arr)
当数据量超过千级、且操作密集(如实时过滤、状态缓存、事件监听器注册表), Map 的 set/get/delete 和 Set 的 add/has/ 平均时间复杂度都是 O(1),而 
Object 的 in 操作受原型链影响,Array 的 includes、indexOf、filter 全是 O(n)。
但要注意:
Array 有深度优化,Map/Set 反而略慢Map 和 Set 实例本身不可 JSON 序列化,若需持久化或跨线程传递(如 postMessage),必须显式转换Map(2) {"a" => 1, "b" => 2},比 Object 层层展开更直观,但无法像对象那样点开看原型