面试题:JavaScript 中 Map 和 Object 的区别是什么?

MapObject 都可以用来存储键值对,但它们在设计、特性和使用场景上有显著区别。理解这些差异对于选择合适的数据结构至关重要。


核心区别对比

特性MapObject
键的类型任意类型(对象、函数、原始值、Symbol)仅限字符串或 Symbol(其他类型会被转换为字符串)
键值对顺序保持插入顺序ES2015+ 保持插入顺序(旧版本无保证)
大小map.size 属性直接获取无内置属性,需手动计算(如 Object.keys(obj).length
可迭代性原生可迭代,可直接用于 for...of 循环不可直接迭代,需使用 Object.keys(), Object.values(), Object.entries()
继承不继承 Object.prototype,是纯粹的键值对集合继承 Object.prototype,可能包含原型链上的属性
性能大量键值对时性能更优(专门优化)小量数据性能良好,大量数据可能变慢
初始化可通过数组或迭代器初始化 new Map([[key1, val1], [key2, val2]])字面量 {} 或构造函数 new Object()

详细说明

1. 键的类型 (Key Types)

这是最根本的区别。

  • Map:键可以是任何类型
const map = new Map();
  const objKey = {};
  const funcKey = function() {};

  map.set(objKey, "value1");
  map.set(funcKey, "value2");
  map.set(42, "value3"); // 数字作为键
  map.set("string", "value4");

  console.log(map.get(objKey)); // "value1"
  • Object:键必须是字符串或 Symbol。如果使用其他类型,会被强制转换为字符串
const obj = {};
  const objKey = {};
  const funcKey = function() {};

  obj[objKey] = "value1";
  obj[funcKey] = "value2";
  obj[42] = "value3";

  // 所有非字符串/非Symbol的键都被转换为字符串 "[object Object]"
  console.log(obj); 
  // { '42': 'value3', '[object Object]': 'value2' }
  // 注意:objKey 和 funcKey 都变成了 "[object Object]",导致冲突!

2. 顺序与迭代 (Order & Iteration)

  • Map保证键值对按照插入顺序进行迭代。
const map = new Map();
  map.set("first", 1);
  map.set("second", 2);

  for (const [key, value] of map) {
    console.log(key, value); // 先 "first" 1, 后 "second" 2
  }
  • Object:在 ES2015 (ES6) 之前,对象属性的顺序是未定义的。现代 JavaScript 引擎通常保持插入顺序,但为了安全和可预测性,最好使用 Object.keys() 等方法获取键数组后再排序或遍历。

3. 获取大小 (Size)

  • Map:提供 size 属性,直接获取键值对数量。
console.log(map.size); // 2
  • Object:没有内置的 lengthsize 属性。需要通过 Object.keys(obj).length 等方式计算,效率较低。

4. 可迭代性 (Iterability)

  • Map:是可迭代对象(Iterable),可以直接在 for...of 循环中使用,返回 [key, value] 数组。
for (const [key, value] of map) { ... }
  • Object不是可迭代对象。不能直接用于 for...of。需要借助:
for (const key of Object.keys(obj)) { ... }
  for (const value of Object.values(obj)) { ... }
  for (const [key, value] of Object.entries(obj)) { ... }

5. 原型与继承 (Prototype & Inheritance)

  • Map:不继承 Object.prototype,是一个纯粹的集合。hasOwnProperty 等方法不会干扰。
  • Object:继承自 Object.prototype,可能包含原型链上的方法(如 toString, hasOwnProperty)。如果键名恰好与这些方法名相同,可能会导致问题或需要特殊处理。

6. 性能 (Performance)

  • Map:在频繁添加/删除键值对存储大量数据时,性能通常优于 ObjectMap 的查找、插入、删除操作经过专门优化。
  • Object:对于少量、静态的配置数据,性能足够好。

使用场景建议

场景推荐使用
键是对象、函数或其他非字符串/非Symbol类型Map
需要保持插入顺序且频繁迭代Map
需要快速获取集合大小Map
存储大量键值对,且频繁增删Map
简单的配置对象、JSON 数据结构Object
需要通过点符号访问属性(如 obj.nameObject
作为函数参数传递配置项Object

总结

  • Object 是 JavaScript 的基础,适合表示实体(如用户、产品)和配置,语法简洁(点符号、字面量)。
  • Map 是 ES6 引入的集合数据结构,适合存储键值对映射,尤其是当键的类型多样、需要保证顺序、或数据量大时。

简单记忆

  • Object属性
  • Map映射

根据具体需求选择合适的数据结构,能写出更高效、更清晰的代码。

THE END
喜欢就支持一下吧
点赞14 分享