含义、基本用法
Map 是 ES6 引入的一种新的数据结构,用于存储键值对。与普通对象不同,Map 的键可以是任何数据类型,包括对象、函数等
// 创建 Map
const myMap = new Map();
// 基本操作
myMap.set('name', 'Alice');
myMap.set(1, 'number one');
myMap.set({}, 'object key');
console.log(myMap.get('name')); // 'Alice'
console.log(myMap.size); // 3
了解为什么在 ES6 引入 Map
JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。
请看看下面代码:
const data = {};
const element = document.getElementById('myDiv');
data[element] = 'metadata';
data['[object HTMLDivElement]'] // "metadata"
上面代码原意是将一个 DOM 节点作为对象data的键,但是由于对象只接受字符串作为键名,所以element被自动转为字符串[object HTMLDivElement],为了解决这个问题,ES6 提供了 Map 数据结构。
它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说:
- Object 结构提供了“字符串—值”的对应
- Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。
如果你需要“键值对”的数据结构,Map 比 Object 更合适。
Map 和 Obj 的区别
| 特性 | Map | Object |
|---|---|---|
| 键的类型 | 任意类型 | 字符串或 Symbol |
| 顺序 | 插入顺序 | 不保证顺序(ES6后有一定顺序) |
| 大小 | size 属性 | 需要手动计算 |
| 性能 | 频繁增删时更优 | 静态数据时更优 |
| 默认键 | 无 | 有原型链上的键 |
Map 的常用方法
1. 基本操作
const map = new Map();
// 添加元素
map.set('name', 'John');
map.set('age', 30);
map.set('isStudent', false);
// 获取元素
console.log(map.get('name')); // 'John'
// 检查是否存在
console.log(map.has('age')); // true
// 删除元素
map.delete('isStudent');
// 清空 Map
// map.clear();
// 获取大小
console.log(map.size); // 2
2. 遍历 Map
Map 结构原生提供三个遍历器生成函数和一个遍历方法
Map.prototype.keys():返回键名的遍历器。Map.prototype.values():返回键值的遍历器。Map.prototype.entries():返回所有成员的遍历器。Map.prototype.forEach():遍历 Map 的所有成员
const userMap = new Map([
['name', 'Alice'],
['age', 25],
['city', 'New York']
]);
// 遍历键
for (let key of userMap.keys()) {
console.log(key); // 'name', 'age', 'city'
}
// 遍历值
for (let value of userMap.values()) {
console.log(value); // 'Alice', 25, 'New York'
}
// 遍历键值对
for (let [key, value] of userMap.entries()) {
console.log(`${key}: ${value}`);
}
// 使用 forEach
userMap.forEach((value, key) => {
console.log(`${key} = ${value}`);
});
/*
console.log():
name = Alice
age = 25
city = New York
*/3.初始化 Map
// 从数组初始化
const map1 = new Map([
['key1', 'value1'],
['key2', 'value2'],
['key3', 'value3']
]);
// 从对象转换
const obj = { a: 1, b: 2, c: 3 };
const map2 = new Map(Object.entries(obj));
// Map 转回对象
const newObj = Object.fromEntries(map2);4. Map 的合并
function mergeMaps(...maps) {
const merged = new Map();
maps.forEach(map => {
map.forEach((value, key) => {
merged.set(key, value);
});
});
return merged;
}
const map1 = new Map([['a', 1], ['b', 2]]);
const map2 = new Map([['b', 3], ['c', 4]]);
const merged = mergeMaps(map1, map2);
// Map(3) {'a' => 1, 'b' => 3, 'c' => 4}
5. Map 的序列化
// Map 转 JSON
function mapToJson(map) {
return JSON.stringify(Array.from(map.entries()));
}
// JSON 转 Map
function jsonToMap(jsonStr) {
return new Map(JSON.parse(jsonStr));
}
const myMap = new Map([['a', 1], ['b', 2]]);
const json = mapToJson(myMap); // '[["a",1],["b",2]]'
const newMap = jsonToMap(json);实际应用
1. 对象关联
// 使用对象作为键
const userPreferences = new Map();
const user1 = { id: 1, name: 'Alice' };
const user2 = { id: 2, name: 'Bob' };
userPreferences.set(user1, { theme: 'dark', language: 'en' });
userPreferences.set(user2, { theme: 'light', language: 'fr' });
console.log(userPreferences.get(user1)); // {theme: 'dark', language: 'en'}
2. 计算出现次数/频率
function countFrequency(arr) {
const frequencyMap = new Map();
arr.forEach(item => {
frequencyMap.set(item, (frequencyMap.get(item) || 0) + 1);
});
return frequencyMap;
}
const numbers = [1, 2, 3, 2, 1, 3, 3, 4, 1];
console.log(countFrequency(numbers));
// Map(4) {1 => 3, 2 => 2, 3 => 3, 4 => 1}
总结
- 当键的类型不确定或多样时,使用 Map
- 需要维护插入顺序时,使用 Map
- 频繁增删操作时,使用 Map
- 简单键值对且键为字符串时,使用 Map Object
评论