Set和Map
Set
Set可以看作是一组key的集合,但不存储value.由于key是不重复的,所以在Set中,没有重复的key。
Set本身就是一个构造函数,所以可使用new来创建Set数据。要创建一个Set,需要提供一个Array作为输入,或直接创建一个空Set.
var s = new Set();
var set = new Set([1,2,3]);
Set中不会含有重复的成员,也不会进行类型转化。
var set = new Set([1, 2, 2, 3, '3']);
set; // Set(4) {1, 2, 3, "3"}
Set的属性和方法
add(val): 添加某个值,返回Set结构本身。
delete(val): 删除某个值,返回一个布尔值,表示删除是否成功。
has(val): 返回一个布尔值,表示该值是否为Set的成员。
clear(val): 返回一个布尔值,表示该值是否为Set的成员。
size: 返回Set实例的成员总数。
var s = new Set();
s.add(1).add(2).add(2);
console.log(s); // Set(2) {1, 2}
s.size; // 2
s.has(1); // true
s.has(2); // true
s.has(3); // false
s.delete(1);
s.has(1); // false
console.log(s); // Set(1) {2}
s.clear();
console.log(s); // Set(0) {}
注意:上面的代码有两次add(2),结果输出的Set中只有一个2,这是因为Set中没有重复的成员。
keys(): 返回键名的遍历器
values(): 返回键值的遍历器
entries(): 返回键值对的遍历器
forEach(): 使用回调函数遍历每个成员
需要特别注意的是,Set的遍历顺序就是插入顺序。
由于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"]
let set = new Set([1, 2, 3]);
set.forEach((value, key) => console.log(value * 2) )
// 2
// 4
// 6
扩展运算符(...)内部使用for...of循环,所以也可以用于 Set 结构。
let set = new Set(['red', 'green', 'blue']);
let arr = [...set];
// ['red', 'green', 'blue']
WeakSet
与Set一样,WeakSet是一个构造函数,可以使用new命令创建WeakSet数据结构。
const ws = new WeakSet();
WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。
let set = new WeakSet(),
key = {};
// 将对象加入 set
set.add(key);
console.log(set.has(key)); // true
// 移除对于键的最后一个强引用,同时从 Weak Set 中移除
key = null;
console.log(set.has(key)); // false
WeakSet必须接受一个对象作为参数,不接受基本类型的数据作为参数
var set = new Set([1,2]);
set; // Set(2) {1, 2}
var weakSet1 = new WeakSet([1,2]); // TypeError: Invalid value used in weak set
var weakSet2 = new WeakSet([[1],[2]]);
weakSet2; // WeakSet {Array(1), Array(1)}
WeakSet结构也有add(value), delete(value), has(value)方法。
Map
JavaScript的对象有个小问题,就是键必须是字符串。但实际上Number或者其他数据类型作为键也是非常合理的。为了解决这个问题,最新的ES6规范引入了新的数据类型Map。
Map是一组键值对的结构,具有极快的查找速度。
举个例子,假设要根据同学的名字查找对应的成绩,如果用Array实现,需要两个Array:
var names = ['Michael', 'Bob', 'Tracy'];
var scores = [95, 75, 85];
如果用Map实现,只需要一个“名字”-“成绩”的对照表,直接根据名字查找成绩。
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael'); // 95
Map结构的属性和方法
** size, set(key, value), get(key), has(key), delete(key), clear() **
const map = new Map();
map.set('foo', true);
map.set('bar', false);
map.size // 2
const m = new Map();
const hello = function() {console.log('hello');};
m.set(hello, 'Hello ES6!') // 键是函数
m.get(hello) // Hello ES6!
遍历方法
- keys():返回键名的遍历器。
- values():返回键值的遍历器。
- entries():返回所有成员的遍历器。
- forEach():遍历 Map 的所有成员。
Map 的遍历顺序就是插入顺序。
const 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"
Map 结构的默认遍历器接口(Symbol.iterator属性),就是entries方法。
Map转化为数组
Map 转为数组最方便的方法,就是使用扩展运算符(...)
const myMap = new Map()
.set(true, 7)
.set({foo: 3}, ['abc']);
[...myMap]
// [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]