Set 集合是一种无重复元素的列表,开发者们一般不会像访问数组元素那样逐一访问每个元素,通常的做法是检测给定的值在某个集合中是否存在。Map 集合内含多组键值对,集合中每个元素分别存放着可访问的键名和它对应的值,Map 集合经常被用于缓存频繁取用的数据。
ES6中的 Set 集合
Set 类型时一种有序列表,其中包含一些相互独立的非重复值,通过Set结合可以快速访问其中的数据,更可有效地追踪各种离散值。
- 创建 Set 集合并添加元素
let set = new Set(); //创建Set集合
set.add(5);
set.add('5');
console.log(set.size); // 2
/*
* 在Set集合中,不会对所有值进行强制的类型转换,数字5和字符串“5”可以作为
两个独立的元素存在,
* 唯一列外的是,Set集合中的+0和-0被认为是相等的。
*/
let set = new Set(),
key1 = {} ,
key2 = {};
set.add(key1);
set.add(key2);
console.log(set.size); //2
/*
* 由于key1和key2不会被转为字符串,他们是两个独立的地址引用,因而他们在Set集合中是两个独立的元素。
*/
let set = new Set();
set.add(5);
set.add('5');
set.add(5);
console.log(set.size); //2
let constructorSet = new Set([1,2,3,4,5,5,5,5,5,5,5]);
console.log(constructorSet.size); //5
/*
* 由于第二次传入的数字5是一个重复值,因此不会被添加到集合中。
* Set集合会过滤掉重复的值从而保证集合中的元素各自唯一。
*/
- 通过has()方法检测Set集合中是否存在某个值
let set = new Set();
set.add(5);
console.log(set.has(5)); //true
console.log(set.has(99)); // false
- 移除元素
let set = new Set();
set.add(6);
set.add(5);
console.log(set.has(5)); // true
set.delete(5); //删除指定元素
console.log(set.has(5)); //false
console.log(set.size); //1
set.clear(); //清空set合集中的所有元素
console.log(set.has(6)); //false
console.log(set.size); // 0
-
Set 集合中的forEach(callback, this)方法
forEach()方法接受一下3个参数:- value 当前值
- key 当前索引值
- 被遍历的Set集合本身
let set = new Set(['a','b']);
set.forEach((value,key,selfSet)=>{
console.log(`Key is ${key} and value is ${value}`);
console.log(selfSet == set)
})
// Key is a and value is a
// true
// Key is b and value is b
// true
如果需要在回调中使用this引用,则可以将它作为第二个参数传入forEach()函数:
let set = new Set([1,2]);
let processor = {
output(value){
console.log(value)
},
process(dataSet){
dataSet.forEach(function(value){
this.output(value)
},this)
}
}
processor.process(set)
// 1
// 2
- 将Set集合转换为数组
let set = new Set([1,2,3,4,5,5,5,5,5]);
let array = [...set];
console.log(array); // [1,2,3,4,5]
以上过程自动移除了数组中的重复值,利用这个特性,可以创建并赋值一个无重复的数组:
function eliminateDuplicates(items){
return [...new Set(items)];
}
let array = [1,1,1,1,2,2,3,4,5,5,5,5,5,5];
let noDuplicates = eliminateDuplicates(array);
console.log(noDuplicates); // [1,2,3,4,5]
Weak Set 集合
Weak Set 集合只存储对象的弱引用,并且不可以存储原始值;集合中的弱引用如果是对象唯一的引用,则会被回收并释放相应内存。
- 创建 Weak Set 集合
let weakSet = new WeakSet(); //创建Weak Set集合
let key = {};
weakSet.add(key); //像Weak Set集合中添加对象
console.log(weakSet.has(key)); // true
weakSet.delete(key); // 删除 Weak Set集合中的key引用
console.log(weakSet.has(key)); //false
let key1 = {};
let key2 = {};
let set = new WeakSet([key1, key2]);
console.log(set.has(key1)); // true
console.log(set.has(key2)); // true
/*
* 向WeakSet构造函数传入一个含有两个对象的数组,最后创建一个包含这两个对象的WeakSet集合
* WeakSet构造函数不接受任何原始值,如果数组中包含其他非对象值,会抛出错误
*/
-
两种 Set 类型的主要区别
两种Set类型之间最大的区别是Weak Set保存的是对象之的弱引用:- 在WeakSet的实例中,如果向add()方法传入非对象参数会导致程序报错,而向has()和delete()方法传入非对象参数则会返回false
- Weak Set 集合不可迭代,所以不能被用于for-of循环
- Weak Set 集合不暴露任何迭代器,所以无法通过程序本身来检测其中的内容
- Weak Set 集合不支持forEach()方法
- Weak Set 集合不支持size属性
ES6中的 Map 集合
ES6中的 Map 类型时一种存储着许多键值对的有序列表,其中的键名和对应的值支持所有的数据类型。键名的等价性判断是通过调用Object.is()方法实现的。
- 创建 Map 集合
let map = new Map();
map.set('name','欧阳不乖'); //接受两个参数:key 和 value
map.set('age',18);
console.log( map.get('name') ); //'欧阳不乖'
console.log( map.get('age') ); //18
console.log( map.get('hobby') ); // undefined 集合中不存在的返回undefined
-
Map 集合支持的方法
- has(key) 检测指定的键名在Map集合中是否存在
- delete(key) 从Map集合中移除指定键名及其对应的值
-
clear() 移除Map集合中所有的键值对
Map 集合同样支持size属性,表示当前集合中包含的键值对的数量
let map = new Map();
map.set('name','欧阳不乖');
map.set('age',18);
console.log(map.size); //2
console.log(map.has('name')); // true
console.log(map.get('name')); // 欧阳不乖
console.log(map.has('age')); // true
console.log(map.get('age')); // 18
map.delete('name'); // 删除name键
console.log(map.has('name')); // false
console.log(map.get('name')); // undefined
console.log(map.size); // 1
map.clear(); //清空所有的集合
console.log(map.has('age')); // false
console.log(map.get('age')); // undefined
console.log(map.size); // 0
-
Map 集合的初始化方法
可以向 Map 构造函数传入数组来初始化一个 Map 集合
let map = new Map([['name', '欧阳不乖'],['age', 18]]);
console.log( map.has('name') ); // true
console.log(map.get('name')); // 欧阳不乖
console.log(map.size); //2
-
Map 集合的forEach()方法
forEach()方法接受一下3个参数:- value 当前值
- key 当前索引值
- 被遍历的Map集合本身
let map = new Map([['name', '欧阳不乖'],['age', 18]]);
map.forEach((value, key, selfMap)=>{
console.log(`Key is ${key} and value is ${value}`);
console.log(selfMap==map )
})
// Key is name and value is 欧阳不乖
// true
// Key is age and value is 18
// true
Map 集合和 Set 集合很类似,充分理解其中一个,另一个自然就明白了。
Weak Map 集合
Weak Map 是弱引 Map 集合,也可用于存储对象的弱引用。Weak Map集合中的键名必须是一个对象,如果使用field对象键名会报错;集合中保存的是这些对象的弱引用,如果弱引用之外不存在其他的强引用,引擎的垃圾回收机制会自动回收这个对象,同时也会移除Weak Map集合中的键值对。
- 使用Weak Map集合
let map = new WeakMap();
let key = {};
map.set( key, 'Here Is Object Desc');
console.log(map.get(key)); // Here Is Object Desc
// 移除key元素
key = null;
// 此时WeakMap集合为空
-
Weak Map集合的初始化方法
调用 WeakMap构造函数并传入一个数组容器,容器内包含其他数组,每一个数组由两个元素构成:第一个元素是一个键名,传入的值必须是非null的对象;第二个元素是这个键对应的值,可以是任意类型:
let key1 = {};
let key2 = {};
let map = new WeakMap( [ [key1, 'Hello'], [key2, 'World'] ] );
console.log(map.has(key1)); // true
console.log(map.get(key1)); // Hello
console.log(map.size ); // undefined
Weak Map 不支持size属性
-
Weak Map集合支持的方法
- has(key) 检测指定的键名在Weak Map集合中是否存在
- delete(key) 从Weak Map集合中移除指定键名及其对应的值
let map = new WeakMap();
let key1 = {};
let key2 = {};
map.set(key1,'欧阳不乖');
map.set(key2,18);
console.log(map.has(key1)); // true
console.log(map.get(key1)); // '欧阳不乖'
map.delete(key1)
console.log(map.has(key1)); // false
console.log(map.get(key1)); // undefined
-
Weak Map集合的使用方法及使用限制
当要在Weak Map 和Map集合之间做出选择时,需要考虑的主要问题是,是否只用对象作为集合的键名,如果是,那么Weak Map集合是最好的选择。