一、Set
ES6提供了新的数据结构Set(集合)。它类似于数组,但是成员的值都是唯一的,集合实现了iterator接口,所以可以使用扩展运算符和 for…of 进行遍历。
Set的属性和方法:

// 创建一个空集合
let s = new Set();
// 创建一个非空集合
let s1 = new Set([1,2,3,1,2,3]);
// 返回集合的元素个数
console.log(s1.size); // 3
// 添加新元素
console.log(s1.add(4)); // {1,2,3,4}
// 删除元素
console.log(s1.delete(1)); //true
// 检测是否存在某个值
console.log(s1.has(2)); // true
// 清空集合
console.log(s1.clear()); //undefined
由于集合中元素的唯一性,所以在实际应用中,可以使用set来实现数组去重:
let arr = [1,2,3,2,1]
Array.from(new Set(arr)) // {1, 2, 3}
可以通过set来求两个数组的交集和并集:
// 模拟求交集
let intersection = new Set([...set1].filter(x => set2.has(x)));
// 模拟求差集
let difference = new Set([...set1].filter(x => !set2.has(x)));
用以下方法可以进行数组与集合的相互转化:
// Set集合转化为数组
const arr = [...mySet]
const arr = Array.from(mySet)
// 数组转化为Set集合
const mySet = new Set(arr)
二、Map
ES6提供了Map数据结构,它类似于对象,也是键值队的集合,但是它的键值的范围不限于字符串,可以是任何类型(包括对象)的值,也就是说, Object 结构提供了“ 字符串—值” 的对应, Map 结构提供了“ 值—值” 的对应, 是一种更完善的 Hash 结构实现。如果需要“ 键值对” 的数据结构, Map 比 Object 更合适。Map也实现了iterator接口,所以可以使用扩展运算符和 for…of 进行遍历。
Map的属性和方法:

// 创建一个空 map
let m = new Map();
// 创建一个非空 map
let m2 = new Map([
['name', 'hello'],
]);
// 获取映射元素的个数
console.log(m2.size); // 1
// 添加映射值
console.log(m2.set('age', 6)); // {"name" => "hello", "age" => 6}
// 获取映射值
console.log(m2.get('age')); // 6
// 检测是否有该映射
console.log(m2.has('age')); // true
// 清除
console.log(m2.clear()); // undefined
需要注意, 只有对同一个对象的引用, Map 结构才将其视为同一个键:
let map = new Map();
map.set(['a'], 555);
map.get(['a']) // undefined
上面代码的set和get方法, 表面是针对同一个键, 但实际上这是两个值, 内存地址是不一样的, 因此get方法无法读取该键, 所以会返回undefined。
由上可知, Map 的键实际上是跟内存地址绑定的, 只要内存地址不一样, 就视为两个键。这就解决了同名属性碰撞( clash) 的问题,在扩展库时, 如果使用对象作为键名, 就不用担心自己的属性与原来的属性同名。
如果 Map 的键是一个简单类型的值( 数字、 字符串、 布尔值), 则只要两个值严格相等, Map 将其视为一个键, 包括0和 - 0。另外, 虽然NaN不严格相等于自身, 但 Map 将其视为同一个键。
let map = new Map();
map.set(NaN, 123);
map.get(NaN) // 123
map.set(-0, 123);
map.get(+0) // 123