在 JavaScript 中,Map
和 WeakMap
都是用于存储键值对的数据结构,但它们有一些关键的不同之处。
Map
Map
是一种可以存储任意类型的键值对的集合。它保持了键值对的插入顺序,并且可以通过键快速查找对应的值。Map
提供了一些非常有用的方法和属性来操作这些数据对:
set(key, value)
: 将一个键值对添加到Map
中。如果键已经存在,则更新其对应的值。get(key)
: 获取指定键的值。如果键不存在,返回undefined
。has(key)
: 检查Map
中是否存在指定的键。delete(key)
: 删除指定键及其对应的值。clear()
: 清空Map
中的所有键值对。size
: 返回Map
中键值对的数量。- 迭代方法:
Map
是可迭代的,你可以使用forEach
、for...of
和其他迭代方法遍历Map
。
示例
let map = new Map();
map.set('key1', 'value1');
map.set('key2', 'value2');
console.log(map.get('key1')); // 输出 'value1'
console.log(map.size); // 输出 2
WeakMap
WeakMap
是一种特殊的 Map
,它的键是弱引用的。这意味着 WeakMap
中的键不会阻止垃圾回收。也就是说,如果 WeakMap
中的键没有其他引用,它们可以被垃圾回收机制回收,这对于避免内存泄漏非常有用。WeakMap
的一些特点包括:
- 键必须是对象: 你只能使用对象作为
WeakMap
的键,而不能使用基本类型(如数字、字符串)。 - 不支持迭代: 由于键是弱引用,
WeakMap
不提供迭代功能,你不能使用forEach
、for...of
等来遍历WeakMap
。 - 没有
size
属性: 由于键的弱引用性质,WeakMap
没有size
属性来返回键值对的数量。 - 只支持
set
、get
、has
和delete
方法: 这些是操作WeakMap
的唯一方法。
示例
let weakMap = new WeakMap();
let obj = {};
weakMap.set(obj, 'value');
console.log(weakMap.get(obj)); // 输出 'value'
obj = null; // 删除对 obj 的引用
// 由于 obj 的引用已被删除,WeakMap 中的条目可以被垃圾回收
总结
Map
是标准的键值对集合,支持任意类型的键,且支持迭代。WeakMap
的键是弱引用,仅支持对象作为键,不支持迭代,主要用于避免内存泄漏。- 实现
Map
和WeakMap
的核心逻辑涉及哈希表和弱引用的处理。虽然 JavaScript 的原生实现是高度优化的,但下面是一些简化的示例代码,用来展示Map
和WeakMap
的基本实现原理。
Map
实现示例
class SimpleMap {
constructor() {
this._keys = [];
this._values = [];
}
set(key, value) {
// Check if key already exists
const index = this._keys.indexOf(key);
if (index !== -1) {
// Update existing key's value
this._values[index] = value;
} else {
// Add new key-value pair
this._keys.push(key);
this._values.push(value);
}
}
get(key) {
const index = this._keys.indexOf(key);
if (index === -1) return undefined;
return this._values[index];
}
has(key) {
return this._keys.indexOf(key) !== -1;
}
delete(key) {
const index = this._keys.indexOf(key);
if (index === -1) return false;
this._keys.splice(index, 1);
this._values.splice(index, 1);
return true;
}
clear() {
this._keys = [];
this._values = [];
}
get size() {
return this._keys.length;
}
}
// Usage
const map = new SimpleMap();
map.set('key1', 'value1');
console.log(map.get('key1')); // 'value1'
console.log(map.size); // 1
map.delete('key1');
console.log(map.size); // 0
WeakMap
实现示例
实现 WeakMap
的核心是处理弱引用,但 JavaScript 中的 WeakMap
使用内建的机制来管理内存。我们可以模拟 WeakMap
的行为,但请注意,这个实现没有实际的弱引用能力,只是为了展示概念。
class SimpleWeakMap {
constructor() {
this._map = new Map();
}
set(key, value) {
if (typeof key !== 'object' || key === null) {
throw new TypeError('WeakMap key must be an object');
}
this._map.set(key, value);
}
get(key) {
if (typeof key !== 'object' || key === null) {
return undefined;
}
return this._map.get(key);
}
has(key) {
if (typeof key !== 'object' || key === null) {
return false;
}
return this._map.has(key);
}
delete(key) {
if (typeof key !== 'object' || key === null) {
return false;
}
return this._map.delete(key);
}
}
// Usage
const weakMap = new SimpleWeakMap();
const obj = {};
weakMap.set(obj, 'value');
console.log(weakMap.get(obj)); // 'value'
解释
-
SimpleMap
:- 使用两个数组
_keys
和_values
分别存储键和值。 set
方法用于插入或更新键值对。get
方法用于获取值。has
方法用于检查键是否存在。delete
方法用于删除键值对。clear
方法用于清空所有键值对。size
属性返回当前键值对的数量。
- 使用两个数组
-
SimpleWeakMap
:- 使用
Map
来存储键值对,只允许对象作为键。 set
、get
、has
和delete
方法分别用于操作键值对。SimpleWeakMap
的实现中,弱引用的概念在实际应用中是通过垃圾回收机制处理的,示例中无法直接模拟。
- 使用
这两个示例简化了真实实现,真实的 Map
和 WeakMap
实现会更复杂,包含许多优化和内存管理的细节。