ES6之Set与Map

为啥引入Set与Map

在ES6之前,当想使用非数值型索引,就会用非数组对象创建所需的数据结构;

ES5中set集合:

1
2
3
4
5
6
var set = Object.create(null);
set.foo = true;
// checking for existence
if (set.foo) {
// code to execute
}

Map集合:

1
2
3
4
5
var map = Object.create(null);
map.foo = "bar";
// retrieving a value
var value = map.foo;
console.log(value); // "bar"

用这种方法的确可以模拟Set集合与Map集合,但这种所有对象的属性名必须是字符串类型,必须确保每个键名都是字符串类型且在对象中是唯一的。如:

1
2
3
4
5
6
7
8
9
var map = Object.create(null);
map[5] = "foo";
console.log(map["5"]); // "foo"
var map = Object.create(null),
key1 = {},
key2 = {};
map[key1] = "foo";
console.log(map[key2]); // "foo"

对于Map集合中,如果它的属性值是假值,则要求使用布尔值的情况下,会被自动转换成false。当在判断Map结合中是否有某些属性场景会有问题:

1
2
3
4
5
6
var map = Object.create(null);
map.count = 0;
// checking for the existence of "count" or for a nonzero value?
if (map.count) {
// code to execute
}

ES6中Set

添加元素

1
2
3
4
let set = new Set();
set.add(5);
set.add("5");
console.log(set.size);

移除元素

1
2
3
4
5
6
7
8
9
10
let set = new Set();
set.add(5);
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();
console.log(set.has("5")); // false
console.log(set.size); // 0

forEach

需要注意的是回调函数中的前两个参数value与key是一样的;

1
2
3
4
5
let set = new Set([1, 2]);
set.forEach(function(value, key, ownerSet) {
console.log(key + " " + value);
console.log(ownerSet === set);
});

转换为数组

在前面的迭代器中有讲到可迭代对象可以展开,同样Set可以:

1
2
3
let set = new Set([1, 2, 3, 3, 3, 4, 5]),
array = [...set];
console.log(array); // [1, 2, 3, 4, 5]

Weak Set集合

为啥要引入Weak Set?先看一个例子:

1
2
3
4
5
6
7
8
9
let set = new Set(),
key = {};
set.add(key);
console.log(set.size); // 1
// eliminate original reference
key = null;
console.log(set.size); // 1
// get the original reference back
key = [...set][0];

上面例子将变量key设置null时消除了对初识对象的引用,但是Set集合却保留了这个引用;

有时我们希望当其他所有引用都不再存在时,让Set集合的这些引用随之消失;为了解决这个问题,ES6额外引入了一个类型:Weak Set集合(弱引用Set集合)。

Weak Set集合只存储对象的弱引用,并且不可以存储原始值;集合中的弱引用如果是对象唯一的引用,则会被回收并释放相应内存;

Weak Set支持add has和delete方法;

1
2
3
4
5
6
7
let set = new WeakSet(),
key = {};
// add the object to the set
set.add(key);
console.log(set.has(key));
set.delete(key);
console.log(set.has(key));

Weak Set与Set区别:

  • Weak Set实例中,只能含有对象参数;非对象参数会报错
  • Weak Set不可迭代;
  • Weak Set不暴露任何迭代器
  • Weak Set不支持forEach方法
  • Weak Set不支持size属性
  • 最大区别是Weak Set保存的是对象的弱引用

ES6中Map

支持的方法has delete clear

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let map = new Map();
map.set("name", "Nicholas");
map.set("age", 25);
console.log(map.size); // 2
console.log(map.has("name")); // true
console.log(map.get("name")); // 'Nicholas'
console.log(map.has("age")); // true
console.log(map.get("age")); // 25
map.delete("name");
console.log(map.has("name")); // false
console.log(map.get("name")); // undefined
console.log(map.size); // 1
map.clear();
console.log(map.has("name")); // false
console.log(map.get("name")); // undefined
console.log(map.has("age")); // false
console.log(map.get("age")); // undefined
console.log(map.size); // 0

Map集合初始化

1
2
3
4
5
6
let map = new Map([["name", "Nicholas"], ["age", 25]]);
console.log(map.has("name")); // true
console.log(map.get("name")); // 'Nicholas'
console.log(map.has("age")); // true
console.log(map.get("age")); // 25
console.log(map.size); // 2

Map集合的forEach

1
2
3
4
5
6
7
8
9
let map = new Map([["name", "Nicholas"], ["age", 25]]);
map.forEach(function(value, key, ownerMap) {
console.log(key + " " + value);
console.log(ownerMap === map);
});
// name Nicholas
// true
// age 25
// true

Weak Map

Weak Map与Map的不同之处和Weak Set与Set的不同类似

  • Weak Map实例中,只能含有对象参数;非对象参数会报错
  • Weak Map不可迭代;
  • Weak Map不暴露任何迭代器
  • Weak Map不支持forEach方法
  • Weak Map不支持size属性,不支持clear
  • 最大区别是Weak Map保存的是对象的弱引用