一、Set

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

Set的属性和方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 创建一个空集合
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来实现数组去重:

1
2
let arr = [1,2,3,2,1]
Array.from(new Set(arr)) // {1, 2, 3}

可以通过set来求两个数组的交集和并集:

1
2
3
4
5
// 模拟求交集
let intersection = new Set([...set1].filter(x => set2.has(x)));

// 模拟求差集
let difference = new Set([...set1].filter(x => !set2.has(x)));

用以下方法可以进行数组与集合的相互转化:

1
2
3
4
5
6
// 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的属性和方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 创建一个空 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 结构才将其视为同一个键:

1
2
3
let map = new Map();
map.set(['a'], 555);
map.get(['a']) // undefined

上面代码的set和get方法, 表面是针对同一个键, 但实际上这是两个值, 内存地址是不一样的, 因此get方法无法读取该键, 所以会返回undefined。

由上可知, Map 的键实际上是跟内存地址绑定的, 只要内存地址不一样, 就视为两个键。这就解决了同名属性碰撞( clash) 的问题,在扩展库时, 如果使用对象作为键名, 就不用担心自己的属性与原来的属性同名。

如果 Map 的键是一个简单类型的值( 数字、 字符串、 布尔值), 则只要两个值严格相等, Map 将其视为一个键, 包括0和 - 0。另外, 虽然NaN不严格相等于自身, 但 Map 将其视为同一个键。

1
2
3
4
5
6
7
let map = new Map();

map.set(NaN, 123);
map.get(NaN) // 123

map.set(-0, 123);
map.get(+0) // 123