在 JavaScript 中,数据结构的选择直接影响代码的性能、可读性与维护性。本文将深入比较 WeakMap
、WeakSet
、Set
、Map
、Object
和 Array
六种常用数据结构的特点、区别及典型应用场景。
一、Array:有序列表
特点
- 按索引(数字)访问元素,适合顺序存储。
- 支持常用操作如:
push
、pop
、shift
、unshift
、splice
。 - 可以存储任意类型元素(包括对象)。
应用场景
- 需要顺序处理的数据集合。
- 需要频繁遍历、排序、筛选的列表。
- 小规模查找(不频繁用索引查找对象)。
示例
js
const list = [1, 2, 3];
list.push(4); // [1,2,3,4]
二、Object:键值对结构(键为字符串或 Symbol)
特点
- 传统的键值对容器,键只能是字符串或 Symbol。
- 原型链可能引发属性冲突(可使用
Object.create(null)
解决)。 - 无法直接遍历,需借助
Object.keys()
、Object.entries()
。
应用场景
- 用作配置对象(key 为已知的字符串标识)。
- 不需频繁添加删除项。
- 键值对较固定时更适合。
示例
js
const config = {
baseUrl: "https://api.example.com",
timeout: 3000
};
三、Set:值的集合(无重复)
特点
- 只存储值,不存储键,值唯一。
- 自动去重。
- 可遍历(支持
forEach
、for...of
)。 - 元素可为任意类型。
应用场景
- 数组去重。
- 检查某个值是否存在(比数组更高效)。
- 需要频繁添加/删除元素且不重复。
示例
js
const ids = new Set([1, 2, 2, 3]);
console.log(ids); // Set(3) {1, 2, 3}
四、Map:键值对结构(键可为任意类型)
特点
- 键可以是对象、函数、任意类型。
- 有序:按照插入顺序保存。
- 遍历友好(支持
forEach
、entries()
)。 - 大数据量下比 Object 更高效。
应用场景
- 需要以对象为键时。
- 有大量键值对操作(增删查改)时。
- 保持键值对插入顺序。
示例
js
const map = new Map();
const objKey = {};
map.set(objKey, "value");
console.log(map.get(objKey)); // "value"
五、WeakMap:弱引用键值对(键只能是对象)
特点
- 键必须是对象,对键的引用是弱引用。
- 不可枚举(无
forEach
、keys
等方法)。 - 键对象被垃圾回收时,WeakMap 自动释放对应的值。
- 无法清空或遍历所有项。
应用场景
- 对象私有属性的存储(封装、隐藏数据)。
- DOM 节点绑定数据,不影响垃圾回收。
- 缓存场景中临时关联对象数据。
示例
js
const wm = new WeakMap();
let el = document.querySelector("#myDiv");
wm.set(el, { clicked: true });
// 当 el 被移除并为 null 后,wm 中对应数据也会被清除
六、WeakSet:弱引用集合(值必须是对象)
特点
- 值必须是对象,并且是唯一的。
- 弱引用存储,不能遍历。
- 没有
size
属性,不支持清空。 - 自动垃圾回收机制。
应用场景
- 跟踪对象是否存在某个状态(如"是否访问过"、"是否处理过")。
- 对象集合存储,但无需手动清理。
- 防止内存泄漏。
示例
js
const ws = new WeakSet();
let user = { name: "Alice" };
ws.add(user);
// 自动释放,当 user 不再引用
七、对比总结
特性 | Array | Object | Set | Map | WeakSet | WeakMap |
---|---|---|---|---|---|---|
键类型 | 数字索引 | 字符串/Symbol | 值 | 任意 | 对象 | 对象 |
值类型 | 任意 | 任意 | 任意 | 任意 | 对象 | 任意 |
是否可迭代 | ✅ | ❌ (需转化) | ✅ | ✅ | ❌ | ❌ |
键值对支持 | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ |
自动去重 | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ |
键是弱引用 | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ |
GC 自动清除 | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ |
典型用途 | 列表、顺序 | 配置对象、JSON | 去重、集合 | 映射表 | 跟踪对象状态 | 私有数据存储 |
八、使用建议
- ✅ 用
Array
做列表,配合filter
、map
、reduce
操作。 - ✅ 用
Object
存储结构化数据,key 是固定字符串时最合适。 - ✅ 用
Set
做去重、快速判断值是否存在。 - ✅ 用
Map
替代复杂Object
,尤其当键可能为对象时。 - ✅ 用
WeakMap
隐藏对象的元数据,或者做私有变量封装。 - ✅ 用
WeakSet
标记对象是否已访问、避免内存泄漏。