当前位置:首页 > 前端 > 正文内容

【JS】Map和Object的区别

virtualman2周前 (08-24)前端67

JavaScript 中的 MapObject 都可以用来存储键值对,但它们在设计、性能和使用场景上有显著的区别。理解这些差异有助于在开发中做出更合适的选择。


1. 键的类型

  • Object:

    • 键只能是字符串Symbol
    • 如果使用其他类型的值作为键(如数字、对象),它们会被自动转换为字符串
      const obj = {};
      obj[1] = 'number key';
      obj[{a: 1}] = 'object key';
      console.log(obj['1']);     // 'number key' (1 被转为字符串 '1')
      console.log(obj['[object Object]']); // 'object key' (对象被转为字符串 '[object Object]')
  • Map:

    • 键可以是任意类型:字符串、数字、布尔值、函数、对象、nullundefined 等。
    • 键的类型和值保持原样,不会发生类型转换。
      const map = new Map();
      map.set(1, 'number key');
      map.set({a: 1}, 'object key');
      map.set('str', 'string key');
      console.log(map.get(1));     // 'number key'
      console.log(map.get({a: 1})); // undefined! (因为是不同对象引用)
      // 但如果用同一个对象引用作为键,则可以获取
      const keyObj = {a: 1};
      map.set(keyObj, 'same object key');
      console.log(map.get(keyObj)); // 'same object key'

2. 原型与继承

  • Object:

    • 所有普通对象都继承自 Object.prototype
    • 这意味着对象上有一些默认的、可枚举的属性(如 toString, hasOwnProperty 等),虽然它们通常在 for...in 循环中被跳过,但在某些情况下可能会引起命名冲突或需要额外检查。
    • 可以创建无原型的对象 (Object.create(null)) 来避免继承问题。
  • Map:

    • Map 是一个纯粹的键值对集合,没有原型链上的默认属性。
    • 它不会与用户定义的键名发生冲突,更加“干净”。

3. 迭代

  • Object:

    • 本身不可迭代,不能直接用于 for...of 循环。
    • 需要通过 Object.keys(), Object.values(), Object.entries() 获取数组后进行迭代。
    • 或者使用 for...in 循环(但会遍历所有可枚举属性,包括继承的)。
      for (const key of Object.keys(obj)) { ... }
      for (const [key, value] of Object.entries(obj)) { ... }
  • Map:

    • 可迭代对象,可以直接用于 for...of 循环。
    • 按照插入顺序遍历键值对。
    • 提供了 .keys(), .values(), .entries() 方法,返回迭代器。
      for (const [key, value] of map) { ... }
      for (const key of map.keys()) { ... }

4. 获取大小

  • Object:

    • 没有内置的 .size 属性。
    • 需要手动计算:Object.keys(obj).length
  • Map:

    • 有内置的 .size 属性,直接返回键值对的数量。
      console.log(map.size); // 直接获取大小

5. 性能

  • Object:

    • 对于少量、静态的键值对,性能良好。
    • 当键的数量非常大时,频繁的增删改查操作性能可能不如 Map,因为 Map 是专门为频繁操作优化的数据结构。
  • Map:

    • 频繁的添加、删除和查找操作中性能通常更优,尤其是在键值对数量很多时。
    • 浏览器引擎对 Map 的内部实现进行了优化。

6. 序列化与解析

  • Object:

    • 可以轻松地使用 JSON.stringify()JSON.parse() 进行序列化和反序列化。
  • Map:

    • 不能直接JSON.stringify() 序列化(会得到 {})。
    • 需要先转换为数组(如 Array.from(map)[...map]),然后再序列化。反序列化后需要重新构造 Map

7. 初始化方式

  • Object:

    • 可以通过对象字面量 {}new Object() 创建。
    • 字面量方式简洁直观。
  • Map:

    • 必须使用 new Map() 创建。
    • 可以传入一个可迭代对象(如数组)来初始化:
      const map = new Map([
          ['key1', 'value1'],
          ['key2', 'value2']
      ]);

8. 删除操作

  • Object:

    • 使用 delete obj.keydelete obj['key'],性能相对较差。
  • Map:

    • 使用 .delete(key) 方法,性能更好。

何时使用?

场景 推荐使用
存储具有逻辑结构的数据,属性名是字符串 Object
需要 JSON 序列化/反序列化 Object
键是字符串或 Symbol,且数量不多 Object
键是任意类型(如对象、函数) Map
需要频繁增删改查大量键值对 Map
需要按插入顺序遍历 Map
需要知道键值对的数量 (size) Map
避免原型污染或默认属性干扰 Map

总结

  • Object 更适合表示实体配置,是 JavaScript 最基础的数据结构。
  • Map 更适合表示集合字典,是一个为高性能键值对操作而设计的专用集合类型。

选择 Map 还是 Object 应根据具体的使用场景、键的类型、性能需求和功能要求来决定。在现代 JavaScript 开发中,Map 在许多场景下是比 Object 更优的选择。

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。