JavaScript 中 Map 和 Object 的选择

最近在阅读 Js 红宝书,读到 Map 和 Object 的选择问题。 这里分享给大家我的学习和总结。

先说结论,增删较多用 Map,查找较多用 Object。

书中详细从 4 个角度比较了两者的差异,这里简要概括一下。

  1. 内存占比: Map 大约比 Object 多存储 50% 的键值对。

  2. 插入性能:Map 稍微快一点,如果有大量插入操作,选 Map。

  3. 查找速度: 如果有大量查找操作,选 Object。(书上写大量数据时 Object 更快,但是测试下来,数据量大时 Map 更快?)

  4. 删除性能:Map 的 删除比 Map 的插入和查找更快, 选 Map。

接下来,用代码验证一下,这些结论是否为真。

1. 比较内存占比

由于内存占比无法直接测量,所以使用间接的方式大致估算一下内存占用。

js 复制代码
//比较内存占比
function measureMemoryUsage(iterations) {
  const obj = {};
  const map = new Map();

  // 填充对象和Map
  for (let i = 0; i < iterations; i++) {
    obj[`key${i}`] = `value${i}`;
    map.set(`key${i}`, `value${i}`);
  }

  // 序列化对象和Map
  const objSerialized = JSON.stringify(obj);
  const mapSerialized = Array.from(map, ([key, value]) => `${key}:${value}`).join(',');

  // 计算大小并比较
  const objSize = new Blob([objSerialized], { type: 'application/json' }).size;
  const mapSize = new Blob([mapSerialized], { type: 'application/json' }).size;

  console.log(`Object size: ${objSize} bytes`);
  console.log(`Map size: ${mapSize} bytes`);
  console.log(`Map is approximately ${(mapSize / objSize) * 100}% of the size of Object`);
}

// 测试插入1000个键值对
measureMemoryUsage(1000);

可以看到,这里 Map 占用的内存大概是 Object 的79%。

2. 比较插入性能

js 复制代码
function testInsertionPerformance() {
  const iterations = 10000; // 测试插入次数
  let startTime = performance.now();

  for (let i = 0; i < iterations; i++) {
    const obj = {};
    obj[`key${i}`] = `value${i}`;
  }

  const objectInsertionTime = performance.now() - startTime;

  startTime = performance.now();

  for (let i = 0; i < iterations; i++) {
    const map = new Map();
    map.set(`key${i}`, `value${i}`);
  }

  const mapInsertionTime = performance.now() - startTime;

  console.log(`Object insertion time: ${objectInsertionTime} ms`);
  console.log(`Map insertion time: ${mapInsertionTime} ms`);
}

testInsertionPerformance();

插入的速度,Map 明显要比 Object 快。

3.比较查找速度

js 复制代码
function testLookupPerformance() {
  const map = new Map();
  const obj = {};

  for (let i = 0; i < 500; i++) {
    map.set(`key${i}`, `value${i}`);
    obj[`key${i}`] = `value${i}`;
  }

  let startTime = performance.now();

  for (let i = 0; i < 500; i++) {
    const value = map.get(`key${i}`);
  }

  const mapLookupTime = performance.now() - startTime;

  startTime = performance.now();

  for (let i = 0; i < 500; i++) {
    const value = obj[`key${i}`];
  }

  const objectLookupTime = performance.now() - startTime;

  console.log(`Map lookup time: ${mapLookupTime} ms`);
  console.log(`Object lookup time: ${objectLookupTime} ms`);
}

testLookupPerformance();

可以看到,当数据较少时,Object 更快。

js 复制代码
function testLookupPerformance() {
  const map = new Map();
  const obj = {};

  for (let i = 0; i < 100000; i++) {
    map.set(`key${i}`, `value${i}`);
    obj[`key${i}`] = `value${i}`;
  }

  let startTime = performance.now();

  for (let i = 0; i < 100000; i++) {
    const value = map.get(`key${i}`);
  }

  const mapLookupTime = performance.now() - startTime;

  startTime = performance.now();

  for (let i = 0; i < 100000; i++) {
    const value = obj[`key${i}`];
  }

  const objectLookupTime = performance.now() - startTime;

  console.log(`Map lookup time: ${mapLookupTime} ms`);
  console.log(`Object lookup time: ${objectLookupTime} ms`);
}

testLookupPerformance();

当数据量增大时,Map 就比 Object 快多了。

4.比较删除性能

js 复制代码
function testDeletionPerformance() {
  const map = new Map();
  const obj = {};

  for (let i = 0; i < 1000000; i++) {
    map.set(`key${i}`, `value${i}`);
    obj[`key${i}`] = `value${i}`;
  }

  let startTime = performance.now();

  for (let i = 0; i < 1000000; i++) {
    map.delete(`key${i}`);
  }

  const mapDeletionTime = performance.now() - startTime;

  startTime = performance.now();

  for (let i = 0; i < 1000000; i++) {
    delete obj[`key${i}`];
  }

  const objectDeletionTime = performance.now() - startTime;

  console.log(`Map deletion time: ${mapDeletionTime} ms`);
  console.log(`Object deletion time: ${objectDeletionTime} ms`);
}

testDeletionPerformance();

当数据量较少时,区别还不明显,当增大到 100 万时,很明显是 Map 胜出。

查找速度仍有疑问,因为测试和书中不一致,问了 kimi。

说法是一样的,那就可能是我的测试用例有问题?

请各位朋友多指教。

相关推荐
志尊宝13 小时前
AI原生前端开发(031):AI辅助的性能分析与瓶颈定位
javascript·人工智能·ai-native
adinnet202613 小时前
持续智能问数:多轮对话状态管理、下钻钻取与经营驾驶舱的演进
javascript·数据库·人工智能
FYKJ_201013 小时前
springboot高考志愿填报推荐系统14332-计算机课程设计、毕业设计
javascript·spring boot·python·架构·django·课程设计·高考
全栈若城13 小时前
从源码拆解一个 AIUI 每日一词智能体:页面、离线索引与硬件交互
javascript
DataGear14 小时前
DataGear 6.1.1 发布,数据可视化分析平台
javascript·信息可视化·数据分析·echarts·数据可视化
Dumbness14 小时前
农历转换的 4 个边界:2 月 30 日能转出"正月十四"、小月没有三十、闰月、立春到春节之间的干支
前端·javascript
系统集成-鹰翔14 小时前
ERP接口月度统计少了零单月份:SQLite分组与最近三个月均值排查
javascript·数据库·经验分享·后端
mONESY14 小时前
从线性 RAG 到 Agentic RAG|基于 LangGraph 实现自主决策 RAG 闭环
javascript·面试
可乐_不渴14 小时前
【Linux】 进程虚拟地址空间
java·linux·javascript
vipxieliang14 小时前
JavaScript 深浅拷贝全解析:从 JSON 到 structuredClone
前端·javascript