Object与Map的区别有哪些?

297 阅读3分钟

在 JavaScript 中,Object 和 Map 都是用于存储 “键值对” 的数据结构,但两者在 键的类型、有序性、迭代方式、性能表现 等核心特性上有显著区别,以下从 6 个关键维度展开对比,并结合场景说明适用场景:

键的类型
  • Object:仅支持 字符串 /.Symbol 作为键(其他类型会自动转为字符串,如 1 → "1"
  • Map:支持 任意类型 作为键(字符串、数字、对象、函数等,键值严格按 “引用 / 值” 比较)
键的有序性
  • Object:ES6 前无序,ES6 后按 “插入顺序” 排列(但数字键会优先按大小排序,存在例外)
const obj = { 
    "a": "aaaa", 
    "1": "1111", 
    "b": "bbbb", 
    "2": "2222" 
}; 
console.log(Object.keys(obj)); // ["1", "2", "a", "b"]
  • Map:严格按 插入顺序 排列,迭代时完全遵循插入顺序(无例外)
const map = new Map()
map.set("b", "bbbb")
map.set("1", "1111")
map.set("a", "aaaa")
map.set("2", "2222")
console.log(Array.from(map.keys())); // ["b", "1", "a", "2"](严格按插入顺序)
迭代方式
  • Object:需通过 for...in(遍历可枚举属性)、Object.keys() 等间接迭代,无法直接遍历键值对
const obj = { name: "张三", age: 80 }; 
// 方式1:for...in(需过滤原型属性)
for (const key in obj) { 
    if (obj.hasOwnProperty(key)) { // 避免遍历原型链上的属性(如 toString)
        console.log(key, obj[key]); // name 张三;age 80
    } 
} 
// 方式2:Object.entries() 转换为数组后迭代 
for (const [key, value] of Object.entries(obj)) { 
    console.log(key, value); // name 张三;age 80
}
  • Map:支持 直接迭代for...offorEach),可直接获取键、值、键值对(entries()
const map = new Map([["name", "张三"], ["age", 80]]);

// 方式1:for...of 遍历键值对
for (const [key, value] of map) {
  console.log(key, value); // name 张三;age 80
}

// 方式2:forEach 遍历
map.forEach((value, key) => {
  console.log(key, value); // name 张三;age 80
});

// 单独遍历键/值
console.log(Array.from(map.keys())); // ["name", "age"]
console.log(Array.from(map.values())); // ["张三", 80]
键值对数量获取
  • Object:需通过 Object.keys(obj).length 间接计算(需遍历所有键)
const obj = { name: '李四', age: 99}
console.log(Object.keys(obj).length) // 输出 2
  • Map:直接通过 size 属性获取(O (1) 时间复杂度,无需遍历)
const map = new Map([['name', '李四'], ['age', 99]])
console.log(map.size) // 2
性能表现
  • Object: 存储少量数据时性能稳定,但频繁增删键值对或存储大量数据时,性能较差。底层通过 “隐藏类” 优化属性访问,但频繁添加 / 删除键值对时,隐藏类会频繁重排,导致性能下降。
  • Map: 频繁增删、查询大量键值对时性能更优(底层基于哈希表,专门优化了频繁操作)
特殊属性/方法
  • 存在原型链继承的 “默认属性”(如 toStringhasOwnProperty),可能与自定义键冲突
  • 无原型链,不存在默认属性,键名完全由用户控制(不会冲突)
适用场景

优先用 Object 的场景:

  1. 存储 简单的键值对(键为字符串,无需复杂类型),如配置项、用户信息({ name: "张三", age: 25 });
  2. 需要 JSON 序列化 / 反序列化JSON.stringify(obj) 可直接转换 Object,Map 需手动处理为数组后才能序列化);
  3. 浏览器兼容性要求极高(如需兼容 IE 浏览器,Map 不支持 IE)。

优先用 Map 的场景:

  1. 键为 非字符串类型(如对象、数字、函数),需避免键自动转换导致的冲突;
  2. 需要 严格按插入顺序迭代 键值对(如日志记录、有序列表);
  3. 频繁进行 增删、查询操作,或存储 大量键值对(如数据缓存、复杂状态管理);
  4. 需避免原型链属性冲突(如自定义键名可能与 Object 原型方法重名)。