Set 与 Map:JavaScript 里的新玩具,比你想象的更好玩!
JavaScript 这门语言,就像一个不断成长的孩子,总会给你带来一些新的惊喜。以前我们用数组和对象来处理各种数据,虽然也能勉强应付,但总感觉有些地方不够灵活,效率也不够高。还好,ES6 带来了 Set 和 Map 这两个新朋友,它们就像乐高积木里的特殊零件,能让你的代码更加优雅,更加高效,也更加…有趣!
想象一下,你是一个幼儿园老师,每天都要点名。以前你可能得遍历整个花名册,一个个比对,生怕漏掉哪个小朋友。现在有了 Set,你只需要把到场的小朋友名字放进 Set 里,然后检查花名册上的名字是否在 Set 里就行了,重复的名字还会自动帮你过滤掉,简直不要太省心!
再想象一下,你要做一个简单的英汉词典。以前你可能用对象来存储单词和释义,但对象的键只能是字符串,如果我想用一个复杂的对象作为键,那就抓瞎了。现在有了 Map,你可以把任何东西都当做键,甚至包括另一个对象!这就像你的百宝箱,想放什么就放什么,再也不用担心空间不够了。
好了,废话不多说,让我们一起走进 Set 和 Map 的世界,看看它们到底有多好玩!
Set:去重小能手,集合操作一把抓
Set,顾名思义,就是集合的意思。它最大的特点就是里面的元素都是唯一的,不允许重复。这就像一个严格的俱乐部,只有符合条件的人才能加入,如果你已经加入了,别人就不能再冒充你。
1. 创建 Set:
创建一个 Set 非常简单,只需要使用 new Set()
就可以了。
const mySet = new Set(); // 创建一个空的 Set
const anotherSet = new Set([1, 2, 3, 4, 5]); // 创建一个包含一些元素的 Set
2. 添加元素:
使用 add()
方法可以向 Set 中添加元素。如果元素已经存在,Set 会自动忽略,不会报错。
mySet.add(1);
mySet.add(2);
mySet.add(3);
mySet.add(1); // 添加重复元素,会被忽略
console.log(mySet); // 输出: Set(3) {1, 2, 3}
3. 删除元素:
使用 delete()
方法可以删除 Set 中的元素。如果元素不存在,也不会报错。
mySet.delete(2);
console.log(mySet); // 输出: Set(2) {1, 3}
4. 检查元素是否存在:
使用 has()
方法可以检查 Set 中是否存在某个元素。
console.log(mySet.has(1)); // 输出: true
console.log(mySet.has(2)); // 输出: false
5. 清空 Set:
使用 clear()
方法可以清空 Set 中的所有元素。
mySet.clear();
console.log(mySet); // 输出: Set(0) {}
6. 获取 Set 的大小:
使用 size
属性可以获取 Set 中元素的个数。
const mySet = new Set([1, 2, 3, 4, 5]);
console.log(mySet.size); // 输出: 5
Set 的进阶玩法:集合操作
Set 不仅仅可以用来去重,还可以进行一些有趣的集合操作,比如并集、交集、差集等等。
- 并集 (Union): 将两个 Set 合并成一个,包含所有元素。
const setA = new Set([1, 2, 3]);
const setB = new Set([3, 4, 5]);
const union = new Set([...setA, ...setB]); // 使用扩展运算符展开 Set
console.log(union); // 输出: Set(5) {1, 2, 3, 4, 5}
- 交集 (Intersection): 找出两个 Set 中共同的元素。
const setA = new Set([1, 2, 3]);
const setB = new Set([3, 4, 5]);
const intersection = new Set([...setA].filter(x => setB.has(x)));
console.log(intersection); // 输出: Set(1) {3}
- 差集 (Difference): 找出只存在于一个 Set 中,而不存在于另一个 Set 中的元素。
const setA = new Set([1, 2, 3]);
const setB = new Set([3, 4, 5]);
// A - B
const differenceAB = new Set([...setA].filter(x => !setB.has(x)));
console.log(differenceAB); // 输出: Set(2) {1, 2}
// B - A
const differenceBA = new Set([...setB].filter(x => !setA.has(x)));
console.log(differenceBA); // 输出: Set(2) {4, 5}
Set 的应用场景:
- 数组去重: 这是 Set 最常见的应用场景,也是它最擅长的事情。
const arr = [1, 2, 2, 3, 4, 4, 5];
const uniqueArr = [...new Set(arr)]; // 使用扩展运算符将 Set 转换成数组
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]
- 跟踪访问过的 URL: 可以使用 Set 来记录用户访问过的 URL,避免重复访问。
const visitedUrls = new Set();
function visitUrl(url) {
if (visitedUrls.has(url)) {
console.log(`已经访问过 URL: ${url}`);
return;
}
console.log(`正在访问 URL: ${url}`);
visitedUrls.add(url);
}
visitUrl('https://www.example.com');
visitUrl('https://www.google.com');
visitUrl('https://www.example.com'); // 提示已经访问过
- 数据验证: 可以使用 Set 来验证数据的唯一性,例如用户名、邮箱地址等。
Map:灵活的键值对,想放啥就放啥
Map 是一种存储键值对的数据结构,它与对象非常相似,但 Map 的键可以是任何数据类型,而对象的键只能是字符串或 Symbol。这就像一个超级灵活的字典,你可以用任何东西来索引你的信息,甚至可以用一幅画,一首歌,或者一个深奥的哲学概念!
1. 创建 Map:
创建一个 Map 也非常简单,只需要使用 new Map()
就可以了。
const myMap = new Map(); // 创建一个空的 Map
const anotherMap = new Map([
['name', 'John'],
['age', 30],
[true, 'isMale']
]); // 创建一个包含一些键值对的 Map
2. 设置键值对:
使用 set()
方法可以向 Map 中添加键值对。
myMap.set('name', 'Alice');
myMap.set('age', 25);
myMap.set(true, 'isFemale');
console.log(myMap); // 输出: Map(3) {"name" => "Alice", "age" => 25, true => "isFemale"}
3. 获取值:
使用 get()
方法可以根据键获取值。如果键不存在,则返回 undefined
。
console.log(myMap.get('name')); // 输出: Alice
console.log(myMap.get('age')); // 输出: 25
console.log(myMap.get('city')); // 输出: undefined
4. 删除键值对:
使用 delete()
方法可以删除 Map 中指定键的键值对。
myMap.delete('age');
console.log(myMap); // 输出: Map(2) {"name" => "Alice", true => "isFemale"}
5. 检查键是否存在:
使用 has()
方法可以检查 Map 中是否存在指定键。
console.log(myMap.has('name')); // 输出: true
console.log(myMap.has('age')); // 输出: false
6. 清空 Map:
使用 clear()
方法可以清空 Map 中的所有键值对。
myMap.clear();
console.log(myMap); // 输出: Map(0) {}
7. 获取 Map 的大小:
使用 size
属性可以获取 Map 中键值对的个数。
const myMap = new Map([
['name', 'John'],
['age', 30]
]);
console.log(myMap.size); // 输出: 2
Map 的进阶玩法:遍历 Map
Map 提供了多种遍历方式,可以方便地访问 Map 中的键和值。
- 使用
for...of
循环: 可以直接遍历 Map 中的键值对,每个键值对都是一个数组,包含键和值。
const myMap = new Map([
['name', 'John'],
['age', 30]
]);
for (const [key, value] of myMap) {
console.log(`Key: ${key}, Value: ${value}`);
}
// 输出:
// Key: name, Value: John
// Key: age, Value: 30
- 使用
forEach()
方法: 类似于数组的forEach()
方法,可以遍历 Map 中的每个键值对。
const myMap = new Map([
['name', 'John'],
['age', 30]
]);
myMap.forEach((value, key) => {
console.log(`Key: ${key}, Value: ${value}`);
});
// 输出:
// Key: name, Value: John
// Key: age, Value: 30
- 使用
keys()
、values()
和entries()
方法: 可以分别获取 Map 中的所有键、所有值和所有键值对,然后使用for...of
循环进行遍历。
const myMap = new Map([
['name', 'John'],
['age', 30]
]);
for (const key of myMap.keys()) {
console.log(`Key: ${key}`);
}
// 输出:
// Key: name
// Key: age
for (const value of myMap.values()) {
console.log(`Value: ${value}`);
}
// 输出:
// Value: John
// Value: 30
for (const entry of myMap.entries()) {
console.log(`Entry: ${entry}`);
}
// 输出:
// Entry: name,John
// Entry: age,30
Map 的应用场景:
- 存储 DOM 元素与数据的关联关系: 可以使用 Map 来存储 DOM 元素与相关数据的关联关系,例如用户 ID、状态等。
const element = document.getElementById('myElement');
const userData = { id: 123, name: 'Alice' };
const elementDataMap = new Map();
elementDataMap.set(element, userData);
console.log(elementDataMap.get(element)); // 输出: {id: 123, name: 'Alice'}
- 缓存计算结果: 可以使用 Map 来缓存计算结果,避免重复计算。
const memoizedFactorial = new Map();
function factorial(n) {
if (memoizedFactorial.has(n)) {
console.log(`从缓存中获取 ${n}!`);
return memoizedFactorial.get(n);
}
if (n === 0) {
return 1;
}
const result = n * factorial(n - 1);
memoizedFactorial.set(n, result);
return result;
}
console.log(factorial(5)); // 输出: 120 (计算并缓存)
console.log(factorial(5)); // 输出: 120 (从缓存中获取)
- 实现 LRU 缓存: LRU (Least Recently Used) 缓存是一种常用的缓存算法,可以使用 Map 来实现。
Set vs Map:选择困难症?
Set 和 Map 都是非常有用的数据结构,但它们的应用场景略有不同。
- Set 专注于存储唯一的值,适用于去重、集合操作等场景。 把它想象成一个只能存放不同玩具的玩具箱。
- Map 专注于存储键值对,适用于需要使用任意数据类型作为键的场景。 把它想象成一个可以贴标签的收纳盒,标签可以是任何东西。
如果你只需要存储一组唯一的值,那么 Set 是更好的选择。如果你需要存储键值对,并且键可以是任何数据类型,那么 Map 是更好的选择。
总结:
Set 和 Map 是 JavaScript 中非常有用的新集合类型,它们提供了更灵活、更高效的数据处理方式。学会使用它们,可以让你写出更优雅、更强大的代码。下次当你需要处理数据时,不妨试试 Set 和 Map,也许它们能给你带来意想不到的惊喜!
希望这篇文章能够帮助你更好地理解 Set 和 Map,并能够在你的日常开发中使用它们。记住,学习新的东西就像打开新的玩具盒,充满了乐趣和惊喜! 玩得开心!