Map 数据结构:存储键值对(任意类型键) (ES6+)
引言
大家好,欢迎来到今天的讲座!今天我们要聊聊 JavaScript 中的 Map
数据结构。如果你已经熟悉了对象(Object
),那么 Map
可能会让你眼前一亮。它不仅提供了更强大的功能,还能解决一些对象无法处理的问题。别担心,我们会用轻松诙谐的方式带你走进 Map
的世界,让你在欢笑中掌握这个强大的工具。
什么是 Map?
在 ES6 之前,JavaScript 中最常用的键值对存储方式是对象(Object
)。对象的键只能是字符串或符号(Symbol
),这限制了它的灵活性。而 Map
是一种新的数据结构,允许你使用 任意类型的键,包括数字、字符串、对象、甚至函数!这使得 Map
在某些场景下比对象更加灵活和强大。
Map 的基本特点
- 任意类型的键:
Map
的键可以是任何类型的数据,不仅仅是字符串或符号。 - 保持插入顺序:
Map
会按照插入的顺序保存键值对,而对象的键是无序的。 - 更好的性能:对于频繁的增删操作,
Map
的性能通常优于对象。 - 内置方法:
Map
提供了许多实用的方法,如set()
、get()
、has()
、delete()
和clear()
等。
创建一个 Map
创建 Map
非常简单,只需要调用 new Map()
即可。你可以通过传递一个数组来初始化 Map
,其中每个元素都是一个包含两个值的数组,分别表示键和值。
// 创建一个空的 Map
const myMap = new Map();
// 通过数组初始化 Map
const fruitPrices = new Map([
['apple', 1.2],
['banana', 0.8],
['orange', 1.5]
]);
console.log(fruitPrices); // Map(3) { 'apple' => 1.2, 'banana' => 0.8, 'orange' => 1.5 }
基本操作
1. 设置键值对 (set()
) 和 获取值 (get()
)
set()
方法用于向 Map
中添加或更新键值对,而 get()
方法用于根据键获取对应的值。
const prices = new Map();
// 设置键值对
prices.set('apple', 1.2);
prices.set('banana', 0.8);
// 获取值
console.log(prices.get('apple')); // 1.2
console.log(prices.get('banana')); // 0.8
2. 检查键是否存在 (has()
)
有时候我们想知道某个键是否存在于 Map
中,这时可以使用 has()
方法。
console.log(prices.has('apple')); // true
console.log(prices.has('grape')); // false
3. 删除键值对 (delete()
)
如果你想删除某个键值对,可以使用 delete()
方法。
prices.delete('banana');
console.log(prices.has('banana')); // false
4. 清空 Map (clear()
)
如果你想清空整个 Map
,可以使用 clear()
方法。
prices.clear();
console.log(prices.size); // 0
迭代 Map
Map
提供了多种迭代方式,方便我们在遍历键值对时进行操作。常见的迭代方法有 keys()
、values()
和 entries()
。
1. 遍历所有键 (keys()
)
keys()
方法返回一个迭代器,遍历 Map
中的所有键。
const fruitPrices = new Map([
['apple', 1.2],
['banana', 0.8],
['orange', 1.5]
]);
for (const key of fruitPrices.keys()) {
console.log(key); // apple, banana, orange
}
2. 遍历所有值 (values()
)
values()
方法返回一个迭代器,遍历 Map
中的所有值。
for (const value of fruitPrices.values()) {
console.log(value); // 1.2, 0.8, 1.5
}
3. 遍历所有键值对 (entries()
)
entries()
方法返回一个迭代器,遍历 Map
中的所有键值对。每个键值对是一个包含两个元素的数组,分别是键和值。
for (const [key, value] of fruitPrices.entries()) {
console.log(`${key}: $${value}`); // apple: $1.2, banana: $0.8, orange: $1.5
}
4. 使用 forEach()
遍历
Map
还提供了一个 forEach()
方法,可以直接遍历所有的键值对,并执行回调函数。
fruitPrices.forEach((value, key) => {
console.log(`${key}: $${value}`);
});
Map 与 Object 的区别
虽然 Map
和对象都可以存储键值对,但它们之间有一些重要的区别。下面是一个简单的对比表格:
特性 | Map |
Object |
---|---|---|
键的类型 | 任意类型(包括对象、函数等) | 只能是字符串或符号(Symbol ) |
插入顺序 | 保持插入顺序 | 不保证顺序 |
性能 | 对于频繁的增删操作性能更好 | 对于小规模数据集性能相似 |
内置方法 | 提供丰富的内置方法(set() 、get() 等) |
内置方法较少,依赖 Object API |
默认属性 | 没有默认属性 | 有默认属性(如 __proto__ ) |
从表格中可以看出,Map
在灵活性和性能方面都优于对象,尤其是在需要使用非字符串键或保持插入顺序的场景下。
实际应用场景
1. 缓存机制
Map
的高效增删特性和保持插入顺序的特点,使得它非常适合用于缓存机制。例如,我们可以使用 Map
来实现一个简单的 LRU(Least Recently Used)缓存。
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.cache = new Map();
}
get(key) {
if (!this.cache.has(key)) return -1;
// 将访问的键移到最后,表示最近使用
const value = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, value);
return value;
}
put(key, value) {
if (this.cache.has(key)) {
this.cache.delete(key);
} else if (this.cache.size >= this.capacity) {
// 移除最早使用的键
this.cache.delete(this.cache.keys().next().value);
}
this.cache.set(key, value);
}
}
const cache = new LRUCache(2);
cache.put('a', 1);
cache.put('b', 2);
console.log(cache.get('a')); // 1
cache.put('c', 3);
console.log(cache.get('b')); // -1 (已移除)
2. 计数器
Map
也可以用于实现计数器,统计某个集合中元素出现的次数。相比于对象,Map
可以直接使用任意类型的键,而不需要将键转换为字符串。
function countOccurrences(arr) {
const counter = new Map();
for (const item of arr) {
counter.set(item, (counter.get(item) || 0) + 1);
}
return counter;
}
const numbers = [1, 2, 3, 2, 1, 3, 4, 1];
const occurrences = countOccurrences(numbers);
console.log(occurrences); // Map(4) { 1 => 3, 2 => 2, 3 => 2, 4 => 1 }
结语
好了,今天的讲座到这里就结束了!希望你对 Map
有了更深入的了解。Map
是一个非常强大且灵活的数据结构,能够帮助你在各种场景下更高效地处理键值对。下次当你遇到需要使用非字符串键或保持插入顺序的需求时,不妨考虑一下 Map
吧!
如果你有任何问题或想法,欢迎在评论区留言讨论。期待下次再见! 😊
参考资料:
- MDN Web Docs: The
Map
object is a simple key/value map. - ECMAScript 2015 (ES6) specification: The
Map
object holds key-value pairs and remembers the original insertion order of the keys.