Map是键可为任意类型的有序键值对容器,Set是基于SameValueZero算法的去重值集合;二者均不支持JSON.stringify直接序列化,需转为数组处理,且在高频操作中提供稳定O(1)性能。

Map 是带键值对的有序集合,不是对象的替代品
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 是去重的值集合,不是数组的简化版
Set 存储唯一值,内部用 SameValueZero 算法判断重复(即 NaN === NaN 为真),而数组靠手动 filter((v, i, a) => a.indexOf(v) === i) 或 [...new Set(arr)] 去重——后者才是 Set 的典型用途。
常见错误现象:
立即学习“Java免费学习笔记(深入)”;
- 误以为
new Set([{a:1}, {a:1}])只存一个对象 → 实际存两个,因对象引用不同 - 用
arr.includes(item)在大数组里频繁查找 → 时间复杂度 O(n),换成set.has(item)是 O(1) -
Set不能通过索引访问元素(没有set[0]),必须用迭代器或转为数组
Map 和 Set 都不支持 JSON.stringify 直接序列化
直接 JSON.stringify(new Map([['a', 1]])) 得到 "{}",JSON.stringify(new Set([1,2])) 也是 "{}"。这是因为它们没有可枚举的自有属性,JSON.stringify 只处理 plain object 的键值对和 array 的索引项。
正确导出方式:
- Map → 转为二维数组:
JSON.stringify([...myMap]) // [["a",1],["b",2]]
- Set → 转为数组:
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 比 Object/Array 更适合高频增删查场景
当数据量超过千级、且操作密集(如实时过滤、状态缓存、事件监听器注册表),Map 的 set/get/delete 和 Set 的 add/has/delete 平均时间复杂度都是 O(1),而 Object 的 in 操作受原型链影响,Array 的 includes、indexOf、filter 全是 O(n)。
但要注意:
- 小数据量(Object 和
Array有深度优化,Map/Set反而略慢 -
Map和Set实例本身不可 JSON 序列化,若需持久化或跨线程传递(如 postMessage),必须显式转换 - 调试时 Chrome 控制台显示
Map(2) {"a" => 1, "b" => 2},比Object层层展开更直观,但无法像对象那样点开看原型










