Object还是Map?

94 阅读3分钟

使用区别

  1. 键类型不同:Object的键只能使用string、number、symbol,Map的键可以是任何类型。

  2. 迭代顺序不同:

    • Map按照键值对插入顺序迭代

    • Object的迭代顺序:

      • for-in循环和Object.keys()根据浏览器有不同表现
      • Object.assign()、Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()枚举顺序确定,先升序枚举数值键,后插入顺序枚举字符串和symbol键。

性能区别

(测试数据基于chrome,速度测试使用performance.now()函数判断,内存使用情况使用Chrome devtool中的memory来查看)
  1. 内存占用

    • Object内存占用更高。存储单个键值对所占用的内存空间随着键数量线性增加,所以给定相同大小的内存空间,Map大约比Object多存储50%的键值对。
    let n, o, m;
    n = 10000;
    while (n--) {
      o = new Object({ 'a': 1, 'a1': 1, 'a2': 1, 'a3': 1, 'a4': 1, 'a5': 1, 'a6': 1, });
    }
    n = 10000;
    while (n--) {
      m = new Map([['a', 1], ['a1', 1], ['a2', 1], ['a3', 1], ['a4', 1], ['a5', 1], ['a6', 1]]);
    }
    // 内存
    class Test { }
    let test = new Test();
    test.o = o;
    test.m = m;
    

    主要观察‘保留的大小’列:

    微信图片_20230405133623.png

  2. 插入性能

    • Map插入速度更快。因为对于两个类型来说,插入速度不是随着键值对的数量呈线性增加,所以对于涉及大量插入操作Map更好。
    let n, n2 = 5, o = new Object(), m = new Map();
    // 速度
    while (n2--) {
      let p1 = performance.now();
      n = 10000;
      while (n--) {
        o[Math.random()] = Math.random();
      }
      let p2 = performance.now();
      n = 10000;
      while (n--) {
        m.set(Math.random(), Math.random());
      }
      let p3 = performance.now();
      console.log(`Object: ${(p2 - p1).toFixed(3)}ms, Map: ${(p3 - p2).toFixed(3)}ms`);
    }
    

    微信图片_20230405133623.png

  3. 查找速度

    • 查找速度差别不大。但是在对象键是连续整数的情况下,浏览器会优化处理,第二个测试案例结果可以看出,速度明显比Map快。所以涉及大量查找操作,Object表现更佳。
    let n, n2 = 5, o = new Object(), m = new Map();
    n = 10000;
    while (n--) {
      o[Math.random()] = Math.random();
    }
    n = 10000;
    while (n--) {
      m.set(Math.random(), Math.random());
    }
    // 速度
    while (n2--) {
      let p1 = performance.now();
      for (let i in o) {
        let k = o[i];
      }
      let p2 = performance.now();
      for (let [key] of m) {
        let k = m.get(key);
      }
      let p3 = performance.now();
      console.log(`Object: ${(p2 - p1).toFixed(3)}ms, Map: ${(p3 - p2).toFixed(3)}ms`);
    }
    

    微信图片_20230405133623.png

    let n, n2 = 5, o = new Object(), m = new Map();
    n = 10000;
    while (n--) {
      o[n] = Math.random();
    }
    n = 10000;
    while (n--) {
      m.set(n, Math.random());
    }
    // 速度
    while (n2--) {
      let p1 = performance.now();
      for (let i in o) {
        let k = o[i];
      }
      let p2 = performance.now();
      for (let [key] of m) {
        let k = m.get(key);
      }
      let p3 = performance.now();
      console.log(`Object: ${(p2 - p1).toFixed(3)}ms, Map: ${(p3 - p2).toFixed(3)}ms`);
    }
    

    微信图片_20230405133623.png

  4. 删除性能

    • 测试结果差异不大。但是高程设计4中表述,Map的删除操作要快于插入和查找,所以Map的删除性能是高于Object的。
    let n, n2 = 5, o = new Object(), m = new Map();
    // 速度
    while (n2--) {
      n = 10000;
      while (n--) {
        o[Math.random()] = Math.random();
      }
      n = 10000;
      while (n--) {
        m.set(Math.random(), Math.random());
      }
      let p1 = performance.now();
      for (let i in o) {
        delete o[i];
      }
      let p2 = performance.now();
      for (let [key] of m) {
        m.delete(key);
      }
      let p3 = performance.now();
      console.log(`Object: ${(p2 - p1).toFixed(3)}ms, Map: ${(p3 - p2).toFixed(3)}ms`);
    }
    

    微信图片_20230405133623.png

如何选择

  1. 选择Map
    • 键值类型是string、number、symbol以外的,需要Map,因为Object不支持
    • 迭代时需要保持插入顺序,选择Map,Object是无序的。
    • 需要存储大量数据时选择Map,相同内存Map存的更多。
    • 需要大量插入删除操作,选择Map,更快
  2. 选择Object
    • 需要JSON转换,使用Object,Map不能直接转换。
    • 需要大量查找操作,使用Object,更快
    • 需要覆盖原型的键,使用Object。
参考

# JavaScript高级程序设计(第4版)

# JS 项目中究竟应该使用 Object 还是 Map?