面试常考: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 更优的选择。

相关推荐
珍宝商店12 小时前
前端老旧项目全面性能优化指南与面试攻略
前端·面试·性能优化
bitbitDown12 小时前
四年前端分享给你的高效开发工具库
前端·javascript·vue.js
YAY_tyy12 小时前
【JavaScript 性能优化实战】第六篇:性能监控与自动化优化
javascript·性能优化·自动化
hsjkdhs13 小时前
万字详解C++之构造函数析构函数
开发语言·c++
gnip13 小时前
实现AI对话光标跟随效果
前端·javascript
Lin_Aries_042114 小时前
容器化简单的 Java 应用程序
java·linux·运维·开发语言·docker·容器·rpc
脑花儿14 小时前
ABAP SMW0下载Excel模板并填充&&剪切板方式粘贴
java·前端·数据库
techdashen14 小时前
12分钟讲解Python核心理念
开发语言·python
闭着眼睛学算法14 小时前
【华为OD机考正在更新】2025年双机位A卷真题【完全原创题解 | 详细考点分类 | 不断更新题目 | 六种主流语言Py+Java+Cpp+C+Js+Go】
java·c语言·javascript·c++·python·算法·华为od
山海不说话14 小时前
Java后端面经(八股——Redis)
java·开发语言·redis