Map数据结构:存储键值对(任意类型键) (ES6+)

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.

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注