在 ES6 中,Map
是一种新的数据结构,它提供了一些原生对象(如普通的 JavaScript 对象)所不具备的特性。以下是 Map
和原生对象之间一些主要的区别:
-
键的类型:
- Map:可以使用任何类型的值(包括对象或原始值)作为键。
- 对象:通常只能使用字符串或者
Symbol
作为键。虽然现代JavaScript引擎会自动将非字符串的键转换为字符串,但这可能导致键的冲突和预期之外的行为。
-
键的顺序:
- Map:键值对是有序的,
Map
对象遍历时会根据元素的插入顺序进行。 - 对象:在 ES2015 之前,对象的属性没有特定的顺序;但从 ES2015 开始,对象的属性遍历顺序是根据属性被添加到对象的顺序(对于字符串键)和整数键的大小来确定的,非整数键则按照创建顺序排列。
- Map:键值对是有序的,
-
大小可获取:
- Map:可以直接获取到
Map
的大小,使用map.size
属性。 - 对象:通常需要手动计算属性的数量,例如通过
Object.keys(obj).length
。
- Map:可以直接获取到
-
性能:
- Map:在频繁添加和删除键值对的场景下,
Map
通常提供更优的性能。特别是当涉及到大量键值对时,Map
的性能通常更稳定。 - 对象:当作为少量属性的集合时,原生对象也可能表现出良好的性能。
- Map:在频繁添加和删除键值对的场景下,
-
默认键:
- Map:不包含默认键,只包含显式插入的键。
- 对象:原型链上的属性和方法可以被继承,对象默认会含有诸如
toString
或hasOwnProperty
这样的方法,这可能会在某些使用场景中造成问题。
-
迭代:
- Map:
Map
对象可以直接被迭代,提供了几个迭代方法,包括map.keys()
、map.values()
和map.entries()
,以及map.forEach()
方法。 - 对象:对象的属性需要使用
for...in
循环或Object.keys()
、Object.values()
、Object.entries()
加上forEach
方法等进行迭代。
- Map:
-
序列化:
- Map:
Map
对象不能直接使用JSON.stringify
进行序列化。 - 对象:对象可以直接被序列化为 JSON 字符串。
- Map:
例如,如果我们需要一个键值对集合来记录用户的唯一标识符(这些标识符可能是数字、字符串、甚至是对象),并且希望保持插入顺序,那么 Map
就特别适合这种用例。使用 Map
我们可以这样实现:
javascriptlet userRoles = new Map(); let user1 = { name: "Alice" }; let user2 = { name: "Bob" }; // 添加用户角色 userRoles.set(user1, 'admin'); userRoles.set(user2, 'editor'); // 获取Map的大小 console.log(userRoles.size); // 2 // 按插入顺序遍历用户角色 for (let [user, role] of userRoles.entries()) { console.log(`${user.name}: ${role}`); }
在这个例子中,我们使用对象 user1
和 user2
作为键,这在普通的对象中是无法做到的,因为对象的键会被转换为字符串。