面试常考:js中 Map和 Object 的区别

MapObject 都是用于存储键值对的数据结构,但它们之间存在许多关键区别。

简单来说,Map 是一个更专门化、功能更强大的键值对集合,而 Object 则是一个更通用的、用于描述实体的基础数据结构。

下面我们从多个维度来详细对比它们的区别。


核心区别对比表

特性 Map Object
键的类型 任意类型(函数、对象、基本类型等) 只能是 String 或 Symbol(其他类型会被自动转换为字符串)
键的顺序 键值对保持插入时的顺序 ES6后: String键按创建顺序;Symbol键无固定顺序。 ES6前: 顺序无保证,因引擎而异。
大小获取 通过 size 属性轻松获取:map.size 需要手动计算:Object.keys(obj).length
迭代 可直接迭代 (是 Iterable 对象),支持 for...of,直接提供 .keys(), .values(), .entries() 方法 默认不可直接迭代 。需要先获取键数组(如Object.keys(obj)),或使用 for...in(会遍历原型链上的可枚举属性)。
默认属性 纯净,不包含任何默认的键值对 有原型 ,可能包含从原型链继承来的属性(如toString, constructor),可能干扰键的访问。
性能 在频繁增删键值对的场景下性能更优 在频繁增删键值对的场景下性能稍差(但具体场景需测试)
序列化 默认没有原生的JSON序列化支持 完美支持 JSON.stringifyJSON.parse

详细解释与示例

1. 键的类型 (Key Type)

这是最根本的区别。

  • Object 的键只能是 StringSymbol 。如果你使用一个非字符串的键(如一个对象),它会被自动通过 .toString() 方法转换为字符串。

    javascript 复制代码
    const obj = {};
    const key = { id: 1 };
    
    obj[key] = 'value'; // key 被转换为字符串 "[object Object]"
    console.log(obj); // { "[object Object]": "value" }
    // 现在你无法再用 key 对象来访问这个值,因为访问时又会转换为相同的字符串
  • Map 的键可以是任何数据类型 ,包括对象、函数、NaN等。它使用"SameValueZero"算法来判断键的相等性(类似于 ===,但认为 NaN === NaN)。

    javascript 复制代码
    const map = new Map();
    const key = { id: 1 };
    
    map.set(key, 'value');
    map.set(NaN, 'This is NaN');
    map.set(() => {}, 'A function as key');
    
    console.log(map.get(key)); // 'value'
    console.log(map.get(NaN)); // 'This is NaN'
    // 键是唯一的,不会发生转换
2. 顺序 (Order)
  • Map 会严格按照键值对的插入顺序来记录和迭代它们。
  • Object 的顺序在 ES6 之前没有明确定义。从 ES6 开始,规范规定了:
    • String 类型的键会按照创建的顺序记录。
    • Symbol 类型的键则没有固定的顺序。
    • 但为了兼容性,最好不要依赖 Object 的属性顺序。
3. 迭代 (Iteration)
  • Map 是一个可迭代对象(实现了 Symbol.iterator),这意味着你可以直接用它来进行 for...of 循环,或者使用展开运算符 ... 将其转换为数组。

    javascript 复制代码
    const map = new Map([['a', 1], ['b', 2]]);
    for (const [key, value] of map) {
      console.log(key, value);
    }
    // Output: a 1, b 2
    
    console.log([...map]); // [ ['a', 1], ['b', 2] ]
  • Object 默认不可直接迭代。你需要使用 Object.keys(), Object.values(), 或 Object.entries() 先获取一个数组,然后再迭代这个数组。

    javascript 复制代码
    const obj = { a: 1, b: 2 };
    for (const key of Object.keys(obj)) {
      console.log(key, obj[key]);
    }
4. 大小 (Size)
  • Map 的大小可以通过 size 属性轻松、高效地获取。

    javascript 复制代码
    console.log(map.size); // 2
  • Object 的大小需要通过 Object.keys(obj).length 来计算,这在性能敏感的场景下可能稍慢。

    javascript 复制代码
    console.log(Object.keys(obj).length); // 2
5. 原型和默认键 (Prototype and Default Keys)
  • Object 可能受到原型链上的属性污染。如果你不小心,可能会覆盖或访问到继承来的方法(如 hasOwnProperty)。你需要使用 obj.hasOwnProperty('key') 来检查一个属性是否是自身的。

    javascript 复制代码
    const obj = {};
    console.log('toString' in obj); // true,因为从原型链继承而来
  • Map 是"纯净"的,它只包含你显式放入的键值对,没有任何默认的键,因此更安全。

    javascript 复制代码
    const map = new Map();
    console.log(map.has('toString')); // false
6. 序列化和解析 (Serialization and Parsing)
  • Object 可以无缝地与 JSON 格式相互转换。

    javascript 复制代码
    const obj = { a: 1 };
    const str = JSON.stringify(obj); // '{"a":1}'
    const newObj = JSON.parse(str); // { a: 1 }
  • Map 默认无法被 JSON.stringify 正确处理,会序列化为一个空对象 {}。你需要自己编写转换逻辑。

    javascript 复制代码
    const map = new Map([['a', 1]]);
    const str = JSON.stringify(map); // '{}'
    
    // 转换 Map -> JSON
    const mapToJson = (map) => JSON.stringify([...map]);
    // 转换 JSON -> Map
    const jsonToMap = (jsonStr) => new Map(JSON.parse(jsonStr));

何时使用 Map vs Object?

使用 Map 的场景:
  1. 键的类型未知或多样:当你需要使用非字符串/符号作为键时(如 DOM 节点、对象等)。
  2. 需要维护插入顺序:并且需要依赖这个顺序进行迭代或其他操作。
  3. 频繁地添加和删除键值对Map 在频繁更新的场景下性能优化得更好。
  4. 需要避免与原型上的键产生冲突:需要一个纯净的键值对集合时。
使用 Object 的场景:
  1. 处理 JSON 数据:需要频繁地进行序列化和反序列化。
  2. 结构是固定的 :你需要一个"实体"来描述某个事物,其属性和方法在开发时就是已知的(例如,user = { name: 'John', age: 30 })。
  3. 需要用到"方法" :对象可以包含函数(方法),而 Map 的值虽然也可以是函数,但语法上不如对象的方法直观(obj.method() vs map.get('method')())。
  4. 使用简单的字符串键 :并且不需要 Map 提供的那些高级特性(如顺序、任意键类型等)。

总结

如果你需要... 那么选择...
存储任意类型的键 Map
保证键值对的插入顺序 Map
频繁地添加/删除元素 Map
纯净的、无原型干扰的集合 Map
简单的结构,已知的字符串键 Object
与 JSON 无缝交互 Object
包含方法(函数) Object

在现代 JavaScript 开发中,当你的需求更偏向于一个纯粹的"键值对集合"或"哈希映射"时,Map 通常是比 Object 更优的选择。

相关推荐
前端小巷子3 小时前
JS实现丝滑文字滚动
前端·javascript·面试
oil欧哟3 小时前
🧐 我用 Vibe Coding 从 0 到 1 打造 AI 产品,上线一个月效果如何?有什么心得?
前端·产品·vibecoding
霍克itxt点top3 小时前
NestJS 入门到实战 前端必学服务端新趋势无密分享
前端
xiguolangzi3 小时前
1panel web服务部署
前端
写不出来就跑路3 小时前
基于 HTML+CSS+JavaScript 的薪资实时计算器(含本地存储和炫酷动画)
javascript·css·html
摘星编程3 小时前
Cursor Pair Programming:在前端项目里用 AI 快速迭代 UI 组件
前端·人工智能·ui·typescript·前端开发·cursorai
程序喵大人4 小时前
写C++十年,我现在怎么设计类和模块?(附真实项目结构)
开发语言·c++·类和模板
黄焖鸡能干四碗4 小时前
信息系统安全保护措施文件方案
大数据·开发语言·人工智能·web安全·制造
醉方休4 小时前
React Fiber 风格任务调度库
前端·javascript·react.js