Set 是不重复值的集合,Map 是键可以是任意类型的对象。
核心两个:
① Set——自动去重,new Set([1,1,2]) 得 {1,2}
② Map——键可以是对象,Map.get(key) / Map.set(key, val)
坑:Set 去重 NaN 也能去、Map 比对象灵活(键不限字符串)、都要用 size 不是 length。
以前去重得写一个空数组,遍历原数组,每看到一个新值才 push 进去——啰嗦。new Set(数组) 自动去重,再用 [...] 展开回数组,一行搞定。
// 有重复的数组
let arr = [1, 2, 3, 4, 4, 3];
// 以前:循环 + indexOf 判断,啰嗦
// 先开个空数组
let unique = [];
// 挨个遍历
arr.forEach(x => {
// 没见过才加
if (unique.indexOf(x) === -1) unique.push(x);
// 现在:new Set 自动去重 + ... 展开回数组
});
// Set 自动去重,... 再拆回数组
let unique = [...new Set(arr)];
// ^^^ 把 Set 重新拆成数组
// [1,2,3,4]
console.log(unique);
new Set(数组) 自动去重,[...set] 再变回数组。这是最常用的数组去重写法,面试必背。
往袋子里扔(add)、拿出来看有没有(has)、扔掉一个(delete)、倒空(clear)、数个数(size)。
// 开个空袋子
let s = new Set();
// 扔进去
s.add("大哥");
// 再扔一个
s.add("二哥");
// 重复的扔不进去,袋子自动忽略
s.add("大哥");
// 2(袋子里现在有几个)
s.size;
// true(有没有这个)
s.has("大哥");
// 扔掉一个 → true
s.delete("二哥");
// 整个袋子倒空
s.clear();
普通对象有个坏习惯:你拿数字当钥匙,它偷偷帮你转成字符串;想拿对象当钥匙?门都没有。Map 不转类型,钥匙原样保留。
// 普通对象:键强制转字符串
// 普通对象
let obj = {};
// 拿数字 123 当键
obj[123] = "数字键";
// {"123": "数字键"} ← 123 被转成 "123" 了
console.log(obj);
// Map:键保持原样,对象也能当键
// 开个 Map
let m = new Map();
// 数字键
m.set(123, "数字键");
// 对象当键,普通对象做不到!
m.set({ id: 1 }, "对象键");
// 数字键
console.log(m.get(123));
Map 的键可以是数字、对象、数组,不会像普通对象那样被强制转成字符串。动态增删键值对、需要用对象/数字当 key 的场景,用 Map 最合适。
// 开个空 Map
let m = new Map();
// 放一对键值
m.set("name", "大喇叭");
// 拿值 → 大喇叭
m.get("name");
// 有没有 → true
m.has("name");
// 删掉一对 → true
m.delete("name");
// 有几对
m.size;
// 全清空
m.clear();
| 对比项 | 普通对象 | Map |
|---|---|---|
| 键的类型 | 只能字符串 / 符号 | 任意类型(数字、对象都行) |
| 遍历 | for...in 比较绕 | forEach 直接遍历,按插入顺序 |
| 常用场景 | 字段固定的数据(如 User) | 动态增删的键值对 |
① 可能在什么地方用:数组去重 [...new Set(arr)]、两个数组求交集/并集、用对象当 key 存关联数据、记录用户访问过的页面。
② 常见的问题:把 Set 当数组直接用 arr[i] 取下标(Set 没有下标);用普通对象存对象键导致 key 全变字符串;遍历 Map 用 for...in 遍历不到。
③ 解决思路:Set 要取下标就先 [...set] 展开;Map 用 m.forEach 或 for...of m;需要对象键就用 Map,别用普通对象。
[...new Set(arr)]。
| API | 作用 | 参数 | 返回值 | 代码示例 |
|---|---|---|---|---|
| new Set(arr) | 把数组扔进自动去重的袋子 | 可遍历对象 | 一个 Set | new Set([1, 1, 2]); |
| .has(x) | 判断袋子里有没有某项 | 要查的值 | true / false | set.has(1); |
| new Map() | 键可以是数字、对象等任意类型的字典 | - | 一个 Map | new Map(); |
| .set(k, v) | 存一个键值对 | 键, 值 | 这个 Map | map.set("a", 1); |
| .get(k) | 按键取值 | 键 | 对应的值 | map.get("a"); |