ES6 标准前,数组一直是JavaScript中常用的数值型索引的集合类型,经常用于队列和栈。而 ES6 新增 Set 集合和 Map 集合,开发者可以使用它们来创建非数值型索引的集合。
一、Set 集合
基本操作
ES6 中 Set 类型是一种有序列表,含有相互独立的非重复值,通过 Set 集合有效地追踪各种离散值。
- 创建Set集合并添加元素
let set = new Set();
set.add(1);
set.add("1");
console.log(set.size); // 2
- 创建 Set 集合并初始化
let set = new Set([1,2,3]);
- 非重复性
let set = new Set([1,2,2,3,3]);
console.log(set.size); // 3
set.add(1); // 已有,添加不成功
console.log(set.size); // 3
- 检查集合是否含有指定元素
let set = new Set([1,2,3]);
console.log( set.has(2) ); // true
console.log( set.has(4) ); // false
- 移除元素
let set = new Set([1,2,3]);
console.log(set.size); // 3
set.delete(1); // 删除成功返回true
console.log(set.size); // 2
set.clear();
console.log(set.size); // 0
为 Set 集合添加元素时,1 和 "1" 可以作为两个独立元素存在的。注意:+0 和 -0 被认为是相等的。 构造函数 Set() 可接受所有可迭代对象作为参数,数值、Set集合、Map集合都是可迭代的。 非重复性:构造函数会过滤重复的值,保持集合元素唯一性,添加已有元素的行为会被忽略。 移除元素:有两种方式,delete() 删除指定元素,clear() 清空集合元素。
遍历操作
- forEach()
forEach 方法相信大家在数组中用得比较多,可以用来简化数组遍历过程,不需要自己写循环语句。ES6 为 Set 集合也添加同样的方法。在数组中,forEach接受三个参数,分别是:元素值、元素索引、数组本身,由于 Set 集合没有键名,ES6 标准委员会为了与数组的 forEach() 保持一致的三个参数,所以第一个参数与第二个参数相同,都能表示元素值。
let set = new Set([1,2,3]);
let fn = function (value){
console.log(value)
}
set.forEach( fn );
- keys(),values(),entries()
keys方法、values方法、entries方法返回的都是遍历器对象。由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。
let set = new Set(['red', 'green', 'blue']);
for (let item of set.keys()) {
console.log(item);
}
// red
// green
// blue
for (let item of set.values()) {
console.log(item);
}
// red
// green
// blue
for (let item of set.entries()) {
console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]
Weak Set 集合
WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有三个区别。
- Weak Set 只能存储对象;
- Weak Set 保存对象弱引用;
- Weak Set 只有add()、has()、delete()方法且不支持size属性,不能遍历。
- WeakSet 的成员只能是对象,而不能是其他类型的值。
let ws = new WeakSet();
ws.add(1)// 报错
ws.add(Symbol())// 报错
上面代码尝试向 WeakSet 增加一个数值和Symbol值,结果报错,因为 WeakSet 只能放置对象。
- Set 集合是一个强引用性的集合,如果我们存储的是对象的话,那 Set 集合就会强引用对象。如果这个对象被废弃,但是 Set 集合还引用了该对象,垃圾回收机制就不能释放该对象内存空间。如果想要垃圾回收机制能处理对象,则首先要切断 Set 集合中对象的引用,才能再切断变量对对象引用。或者使用delete() 或 clear() 清空。
let object = {};
let set = new Set([object]);
console.log(set.size); // 1
set.delete(object);
console.log(set); // 0
object = null;
上面的代码能切断Set集合中对象的引用,但在操作麻烦,object置null前,要先用其切断Set对象引用。
而ES6 新增的WeakSet 中对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。
let object = {};
let ws = new WeakSet([object]);
object = null;
console.log(ws.size); // undefined,注意WeakSet没有这个属性
- WeakSet 没有size属性,没有办法遍历它的成员。
let ws = new WeakSet();
ws.size // undefined
ws.forEach // undefined
ws.forEach(function(item){
console.log('WeakSet has ' + item)}) //报错
}
二、Map 集合
ES6 之前,我们使用对象键值对只能用字符串当作键,这给我们使用带来了很大的限制,而 ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应。
let m = new Map();
let o = {p: 'Hello World'};//创建对象
m.set(o, 'content')
m.get(o) // 对象o可作为“键”,赋值"content"
基本操作
- 创建Map集合并添加、获取键值对
let map = new Map();
map.set("key","value");
console.log(map.get("key")); // value
- 创建Map集合并初始化
let map = new Map([["key1","value1"], ["key2","value2"]]);
console.log(map.get("key1")); // value1
console.log(map.get("key2")); // value2
- 非重复性
let map = new Map([["key","value1"], ["key","value2"]]);
console.log(map.get("key")); // value2
- 检查集合是否含有指定的键
let map = new Map([["key1","value1"]]);
console.log( map.has("key1") ); // true
console.log( map.has("key") ); // false
- 移除键值对
let map = new Map([["key1","value1"], ["key2","value2"]]);
console.log(map.size); // 2
map.delete("key1"); // 删除成功返回true
console.log(map.size); // 1
map.clear();
console.log(map.size); // 0
遍历方法
和 Set 类似,Map 也有forEach()、keys()、values()、entries() 四个遍历的方法,需要注意的是,Map 的遍历顺序就是插入顺序。
onst map = new Map([
['F', 'no'],
['T', 'yes'],
]);
for (let key of map.keys()) {
console.log(key);
}
// "F"
// "T"
for (let value of map.values()) {
console.log(value);
}
// "no"
// "yes"
for (let item of map.entries()) {
console.log(item[0], item[1]);
}
// "F" "no"
// "T" "yes"
// 或者
for (let [key, value] of map.entries()) {
console.log(key, value);
}
// "F" "no"
// "T" "yes"
// 等同于使用map.entries()
for (let [key, value] of map) {
console.log(key, value);
}
// "F" "no"
// "T" "yes"
Weak Map 集合
WeakMap 结构与 Map 结构类似,也是用于生成键值对的集合。和 Set 和 Weak Set 的区别类似,前者之间也存在着以下几点差别:
- Weak Map 只接受对象作为键名(null除外),不接受其他类型的值作为键名。
- Weak Map 键名所指向的对象,不计入垃圾回收机制,即为弱引用对象。
- Weak Map 没有遍历操作(即没有keys()、values()和entries()方法),也没有size属性。
let wm = new WeakMap();
// size、forEach、clear 方法都不存在
wm.size // undefined
wm.forEach // undefined
wm.clear // undefined