聊聊 JS Map 中你可能不知道的几个知识点!
@zs.duan
聊聊 JS Map 中你可能不知道的几个知识点!
阅读量:83
2025-05-08 11:37:51

一、Map 的基本原理

Map 是 JavaScript 中的一种数据结构,它提供了一种键值对的存储方式。与普通的对象相比,Map 具有以下特点:

  1. 键可以是任意类型(包括对象)
  2. 键是唯一
  3. 保持插入顺序
  4. 可以轻松获取大小(通过 size 属性)
  5. 提供了丰富的操作方法

基本使用示例:

const map = new Map();
map.set('key1', 'value1');
map.set('key2', 'value2');
console.log(map.get('key1')); // 'value1'
console.log(map.size); // 2

二、Map 的 size 属性详解

Map 的 size 属性表示 Map 中键值对的数量,而不是字节大小。它与 Buffer 没有直接关系。

size 的含义:

  • size 表示 Map 中键值对的数量
  • 每次调用 set() 方法添加新的键值对时,size 会增加
  • 每次调用 delete() 方法删除键值对时,size 会减少
  • 调用 clear() 方法时,size 会变为 0

与 Buffer 的区别:

  • Buffer 用于处理二进制数据,length 属性表示字节数
  • Map 的 size 只表示键值对的数量
  • 如果需要计算 Map 占用的内存大小,需要手动计算每个键值对的大小

计算 Map 实际内存占用的方法:

function getMapMemorySize(map) {
    let totalSize = 0;
    map.forEach((value, key) => {
        // 计算键的大小
        if (typeof key === 'string') {
            totalSize += Buffer.byteLength(key);
        } elseif (key instanceof Buffer) {
            totalSize += key.length;
        }
        
        // 计算值的大小
        if (typeof value === 'string') {
            totalSize += Buffer.byteLength(value);
        } elseif (value instanceof Buffer) {
            totalSize += value.length;
        } elseif (typeof value === 'object') {
            totalSize += Buffer.byteLength(JSON.stringify(value));
        }
    });
    return totalSize;
}

之前看组员编写代码时就未考虑键的大小计算,这里需要注意下!

注意事项:

  • Map 的 size 属性是实时的,会随着 Map 的变化而更新
  • size 属性是只读的,不能直接修改
  • 如果需要限制 Map 的大小,需要手动实现

二、Map 的 forEach 遍历

Map 提供了 forEach 方法用于遍历,其语法为:

map.forEach((value, key, map) => {
    // 处理逻辑
});

这里有一个看似反直的设计:参数顺序是 (value, key),而不是 (key, value)。这种设计的原因在于:

  1. 保持一致性:

    所有集合类型的 forEach 的第一个参数都是值,保持了 API 的一致性。

    • Array 的 forEach 是 (value, index, array)
    • Set 的 forEach 是 (value, value, set)
    • Map 的 forEach 是 (value, key, map)
  2. 使用频率:

    • 在遍历时,通常更关注值而不是键
    • 把值放在第一个参数位置可以让代码更简洁

三、Map 的其他遍历方法

除了 forEachMap 还提供了多种遍历方式:

for...of 遍历 entries()

for (const [key, value] of map.entries()) {
    console.log(key, value);
}

for...of 遍历 keys()

for (const key of map.keys()) {
    console.log(key);
}

for...of 遍历 values()

for (const value of map.values()) {
    console.log(value);
}

直接遍历 Map(等同于 entries()):

for (const [key, value] of map) {
    console.log(key, value);
}

四、Map 的应用场景

Map 在以下场景中特别有用:

  1. 缓存系统:

    • 使用 Map 存储缓存数据
    • 键可以是复杂的对象
    • 可以轻松管理缓存大小
  2. 数据映射:

    • 需要将一种数据映射到另一种数据
    • 保持数据的对应关系
  3. 对象关联:

    • 当需要将对象作为键时
    • 普通对象只能使用字符串作为键
  4. 频率统计:

    • 统计元素出现次数
    • 快速查找和更新
  5. 配置管理:

    • 存储配置信息
    • 支持动态更新

五、Map 与 Object 的比较

特性
Map
Object
键的类型
任意类型
字符串或 Symbol
键的顺序
保持插入顺序
不保证顺序
大小获取
size
 属性
需要手动计算
性能
频繁增删时更好
少量数据时更好
序列化
需要特殊处理
直接支持 JSON

六、最佳实践建议

  1. 当键是字符串时,优先使用 Object
  2. 当需要非字符串键时,使用 Map
  3. 需要频繁增删操作时,使用 Map
  4. 需要保持插入顺序时,使用 Map
  5. 需要统计大小时,使用 Map
 
评论:

还没有人评论 快来占位置吧