Object 与 Map 的区别

JavaScript 中 Object 和 Map 两种数据结构的对比与使用场景

问题

Object 与 Map 有什么区别?应该如何选择使用?

解答

基本概念

Object 是 JavaScript 中的顶级对象,也是一个构造函数。所有对象都是 Object 的实例,可以通过字面量 {}new Object() 创建。

Map 是 ES6 引入的数据结构,用于解决 Object 只能使用字符串作为键的限制。Map 的键可以是任意类型的值,包括对象、函数等,提供了真正的”值—值”映射。

// Object 创建
const obj = {};
const obj2 = new Object();

// Map 创建
const map = new Map();

主要区别

键的类型

Object 的键只能是字符串、数字或 Symbol,而 Map 的键可以是任意类型:

const obj = {};
obj[{ a: 1 }] = 'value'; // 键会被转为 "[object Object]"
console.log(obj); // { "[object Object]": "value" }

const map = new Map();
map.set({ a: 1 }, 'value'); // 对象可以直接作为键
map.set(function() {}, 'function key'); // 函数也可以作为键

访问方式

// Object
const obj = { name: 'Alice' };
console.log(obj.name); // "Alice"
console.log(obj['name']); // "Alice"
console.log(obj.age); // undefined

// Map
const map = new Map();
map.set('name', 'Alice');
console.log(map.get('name')); // "Alice"
console.log(map.get('age')); // undefined

赋值方式

// Object
obj.name = 'Bob';
obj['age'] = 25;

// Map
map.set('name', 'Bob');
map.set('age', 25);
map.set({ id: 1 }, 'complex key'); // 支持复杂类型的键

删除属性

// Object
const obj = { a: 1 };
delete obj.a; // true
delete obj.b; // true(即使属性不存在也返回 true)

// Map
const map = new Map([['a', 1]]);
map.delete('a'); // true
map.delete('b'); // false(属性不存在返回 false)

获取大小

// Object
const obj = { a: 1, b: 2, c: 3 };
console.log(Object.keys(obj).length); // 3
console.log(Reflect.ownKeys(obj).length); // 3

// Map
const map = new Map([['a', 1], ['b', 2], ['c', 3]]);
console.log(map.size); // 3

迭代方式

// Object(需要转换)
const obj = { a: 1, b: 2, c: 3 };
for (let key in obj) {
  console.log(key, obj[key]);
}
Object.keys(obj).forEach(key => {
  console.log(key, obj[key]);
});

// Map(原生支持迭代)
const map = new Map([['a', 1], ['b', 2], ['c', 3]]);
for (let [key, value] of map) {
  console.log(key, value); // 遍历顺序与插入顺序一致
}
map.forEach((value, key) => {
  console.log(key, value);
});

使用场景

使用 Object

  • 简单的键值对存储,键为字符串或 Symbol
  • 需要 JSON 序列化(JSON.stringify 不支持 Map)
  • 需要使用对象字面量语法

使用 Map

  • 键需要使用复杂类型(对象、函数等)
  • 需要频繁增删操作
  • 需要保持插入顺序
  • 需要快速获取元素数量
// JSON 序列化示例
const obj = { a: 1, b: 2 };
JSON.stringify(obj); // '{"a":1,"b":2}'

const map = new Map([['a', 1], ['b', 2]]);
JSON.stringify(map); // '{}' (无法正确序列化)

// 需要转换
JSON.stringify(Array.from(map.entries())); // '[["a",1],["b",2]]'

关键点

  • Map 的键可以是任意类型,Object 的键只能是字符串、数字或 Symbol
  • Map 通过 size 属性直接获取大小,Object 需要通过 Object.keys() 转换
  • Map 原生支持迭代器,遍历顺序与插入顺序一致,Object 的遍历顺序不确定
  • Map 的 delete 方法会返回布尔值表示是否删除成功,Object 的 delete 操作符即使属性不存在也返回 true
  • Map 不支持 JSON 序列化,需要 JSON 转换的场景只能使用 Object