ES6中Set的用法

参考:阮一峰 ES6入门之Set

ES6 提供了新的数据结构 Set。
它类似于数组,但是成员的值都是唯一的,没有重复的值。

const s = new Set();

[2,3,5,4,5,2,2].forEach(x => s.add(x));
// Set结构不会添加重复的值

for(let i of s) {
  console.log(i);
}

// ## 初始化
// 例一 可以接受一个数组作为参数
const set = new Set([1,2,3,4,4,]);

// ...将一个数组转为用逗号分隔的参数序列
console.log([...set]);

// 例二
const items = new Set([1,2,3,4,5,5,5,5,]);
console.log(items.size);


// 例三 可以接受具有iterable接口的其他数据结构作为参数
const set2 = new Set(document.querySelectorAll('div'));
console.log(set.size);

// 类似于
const set2 = new Set();
document
    .querySelectorAll('div')
    .forEach(div => set.add(div));
console.log(set.size);

// set中NaN等于自身,其余比较相当于 ===
let set3 = new Set();
let a = NaN;
let b = NaN;
set3.add(a);
set3.add(b);
console.log(set3)

// 两个对象总是不相等的
let set4 = new Set();
set4.add({});  // 1
console.log(set4.size);

set4.add({});  // 2
console.log(set4.size);
const s = new Set();

s.add(1).add(2).add(2);

console.log(s.size);

console.log(s.has(1));
console.log(s.has(2));
console.log(s.has(3));

s.delete(2);
console.log(s.has(2));

// set转数组
const items = new Set([1,2,3,4,5]);
const array = Array.from(items);
console.log(array);

// 去除数组重复成员
function dedupe(array) {
  return console.log(Array.from(new Set(array)));
}

dedupe([1,1,2,3]);
let set = new Set(['red', 'green', 'blue']);

// 返回键名
for(let item of set.keys()) {
  console.log(item);
}

// 返回键值
for(let item of set.values()) {
  console.log(item);
}
// set 键名=键值

// 返回键值对
for(let item of set.entries()){
  console.log(item);
}

// 可以直接用 for of遍历Set
// for in 和 for of的区别是:in 是遍历对象,of是遍历值
for (let x of set) {
  console.log(x);
}

// set也有forEach()方法
set.forEach((value, key) => console.log(key + ' : ' + value));
// 此处forEach方法的参数是一个处理函数。

// 数组的 map 和 filter 方法也可以间接用于Set
let s = new Set([1,2,3]);

// map 将原数组映射成新数组
s = new Set([...s].map(x => x * 2));
console.log(s);

// filter返回过滤后的新数组
s = new Set([...s].filter(x => (x % 3) ==0));
console.log(s);

// 实现并集、交集、差集
let a = new Set([1,2,3]);
let b = new Set([4,3,2]);

let union = new Set([...a, ...b]);
console.log(union);

let intersect = new Set([...a].filter(x => b.has(x)));
console.log(intersect);

let difference = new Set([...a].filter(x => !b.has(x)));
console.log(difference);

// 在遍历操作中,同步改变原来的Set结构的两种变通方法

// 1.利用原Set结构映射出一个新的结构,然后赋值给原来的Set结构
let set1 = new Set([1,2,3]);
set1 = new Set([...set1].map(val => val *2));
console.log(set1);

// 2.利用Array.from
let set2 = new Set([1,2,3]);
set2 = new Set(Array.from(set2, val => val * 2));
console.log(set2);

————————————————
版权声明:本文为优快云博主「DurianPudding」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/DurianPudding/article/details/88116732

<think>好的,用户现在想了解ES6中Map和Set用法。我需要先回顾这两个数据结构的特性和常见用法。 首先,用户之前的问题是关于如何判断变量是对象还是数组,现在转向ES6的新数据结构,可能是在开发过程中遇到了需要更高效的数据处理方式,或者想优化现有代码。Map和Set作为ES6新增的集合类型,和传统的对象和数组相比,有各自的优势。 Map类似于对象,但键可以是任意类型,而不仅限于字符串或Symbol。这可能是用户需要的关键点。需要说明Map的基本操作,如set、get、has、delete等,以及它的迭代方法,比如forEach、keys、values、entries。还要提到与普通对象的区别,比如顺序性、性能、序列化等。 然后是Set,它存储唯一值,可以用来数组去重。需要介绍add、has、delete等方法,以及size属性。此外,可以对比数组和Set在查找、去重方面的性能差异,可能用户在处理大量数据时需要高效的去重方法。 用户可能还想知道什么时候使用Map而不是对象,什么时候使用Set而不是数组。比如需要维护插入顺序、需要更快的查找速度时,或者键不是字符串的情况。此外,可能需要提到WeakMap和WeakSet,但用户的问题没有明确提到,所以暂时简要提及即可。 另外,用户可能在实际应用中遇到了一些问题,比如用对象作为键的需求,或者需要高效判断元素是否存在,这时候Map和Set就能派上用场。要举一些实际的例子,比如缓存管理、事件监听器存储、数据去重等场景。 需要确保回答结构清晰,分点说明,可能用代码示例来展示用法。同时,注意比较Map/Set与传统结构的区别,帮助用户理解适用场景。还要注意ES6的兼容性,不过现在大多数环境都支持,可能用户已经使用Babel等工具,所以可以不用深入讨论兼容性问题。 最后,检查是否有遗漏的重要特性,比如Map和Set的迭代顺序是插入顺序,而对象则没有保证。这可能对某些应用场景很重要,比如需要按插入顺序处理数据的情况。 总结下来,回答的结构应该是先介绍Map和Set的基本概念,然后分别详细说明它们的用法、方法、特性,再比较它们与传统结构的区别,最后给出使用场景和示例。这样用户能逐步理解并知道何时使用这些数据结构。</think>以下是关于ES6中Map和Set的深度解析与专业实践指南: --- ### 核心概念对比 | 特性 | Map | Set | 传统结构 | |--------------------|-------------------------|-------------------------|-------------------| | 键类型 | 任意类型 | 值即键 | 字符串/Symbol | | 元素唯一性 | 键唯一 | 值唯一 | 无强制约束 | | 顺序性 | 严格插入顺序 | 严格插入顺序 | 对象无序/数组有序 | | 查找性能 | O(1) | O(1) | 对象O(1)/数组O(n) | | 序列化 | 需特殊处理 | 需特殊处理 | 原生支持JSON | --- ### Map深度解析 **核心方法:** ```javascript const map = new Map(); // 键值设置 map.set('name', 'John') // 字符串键 .set(2023, '年份') // 数字键 .set({id:1}, '对象键'); // 对象键 // 值获取与检测 console.log(map.get('name')); // "John" console.log(map.has(2023)); // true // 删除与清空 map.delete({id:1}); // 失败(对象引用不同) const keyObj = {id:1}; map.set(keyObj, '正确删除方式'); map.delete(keyObj); // 成功 map.clear(); // 清空所有条目 ``` **高级特性:** ```javascript // 1. 链式调用 map.set(1, 'a').set(2, 'b').set(3, 'c'); // 2. 迭代器接口 for(const [key, value] of map) { console.log(`${key}: ${value}`); } // 3. 转换数组 const entriesArray = Array.from(map.entries()); // 4. 对象转换 const objMap = Object.fromEntries(map.entries()); ``` --- ### Set专业实践 **核心操作:** ```javascript const set = new Set(); // 值管理 set.add(5) // 添加数字 .add('text') // 添加字符串 .add({name: 'obj'}); // 添加对象 console.log(set.size); // 3 console.log(set.has(5)); // true set.delete('text'); // 删除元素 ``` **高级应用:** ```javascript // 1. 数组去重(优于传统方法) const uniqueArray = [...new Set([1,2,2,3,4,4])]; // [1,2,3,4] // 2. 集合运算 const setA = new Set([1,2,3]); const setB = new Set([2,3,4]); // 并集 const union = new Set([...setA, ...setB]); // 交集 const intersection = new Set([...setA].filter(x => setB.has(x))); // 差集 const difference = new Set([...setA].filter(x => !setB.has(x))); ``` --- ### 性能关键测试(百万级数据) ```javascript // Map查找 vs 对象查找 const map = new Map(); const obj = {}; let value; // 填充数据 for(let i=0; i<1e6; i++){ map.set(i, `value${i}`); obj[i] = `value${i}`; } console.time('Map查找'); value = map.get(999999); console.timeEnd('Map查找'); // ~0.01ms console.time('对象查找'); value = obj[999999]; console.timeEnd('对象查找'); // ~0.008ms // Set包含检查 vs 数组includes const set = new Set([...Array(1e6).keys()]); const arr = [...Array(1e6).keys()]; console.time('Set检查'); set.has(999999); // ~0.005ms console.timeEnd('Set检查'); console.time('数组检查'); arr.includes(999999); // ~5.2ms console.timeEnd('数组检查'); ``` --- ### 工程实践场景 **场景1:DOM节点元数据存储** ```javascript // 传统方式污染DOM document.querySelector('.btn').metadata = {count: 0}; // 推荐Map方案 const nodeMap = new Map(); const btn = document.querySelector('.btn'); nodeMap.set(btn, {count: 0, timestamp: Date.now()}); ``` **场景2:请求缓存控制** ```javascript const apiCache = new Map(); async function fetchData(url) { if(apiCache.has(url)) { return apiCache.get(url); } const response = await fetch(url); const data = await response.json(); apiCache.set(url, { data, timestamp: Date.now() }); return data; } ``` **场景3:用户行为追踪** ```javascript const userActions = new Set(); function trackAction(action) { if(userActions.has(action)) { console.log('重复操作:', action); return; } userActions.add(action); analytics.send(action); } ``` --- ### 特殊变体说明 **WeakMap与WeakSet:** - 仅接受对象作为键 - 不可迭代 - 自动垃圾回收(无内存泄漏风险) ```javascript const weakMap = new WeakMap(); const element = document.getElementById('app'); weakMap.set(element, { clicks: 0 }); element.addEventListener('click', () => { const data = weakMap.get(element); data.clicks++; }); ``` --- ### 最佳实践原则 1. **键类型策略:** - 优先使用原始类型作为Map键 - 对象键需保持引用稳定 2. **内存管理:** - 大型集合及时清理无用条目 - 使用WeakMap处理DOM关联数据 3. **性能优化:** - 避免在循环中频繁创建新集合 - 对稳定数据集进行预填充 4. **类型转换技巧:** ```javascript // Map转嵌套数组 const mapToArray = [...map].map(([k,v]) => [k, v]); // Set转排序数组 const sortedArray = [...set].sort((a,b) => a - b); ``` 5. **浏览器兼容方案:** ```javascript // Polyfill示例(开发环境自行实现) if (!Map.prototype.forEach) { Map.prototype.forEach = function(callback) { let entries = [...this.entries()]; for(let [key, value] of entries) { callback(value, key, this); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值