在 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 作为键,这在普通的对象中是无法做到的,因为对象的键会被转换为字符串。