ES6-Set & Map
Set
基本概念
Set
用于存放任何类型的对象或值,内部元素的值都是唯一的
Set
本身是一个构造函数,可以用new
生成新的Set
数据结构,可以接受数组或类数组(具有iterable
接口)为参数
1 | let s = new Set([1, 1, 2, 2, 3, 3, 4, 4]); |
通过Array.from
可以将Set
转换为数组
1 | let s = new Set([1, 2, 3, 4]); |
可以通过将数组转换为Set
在转为数组来进行去重
1 | let arr = [1, 1, 2, 2, 3, 3, 4, 4]; |
有两个需要注意的地方:
在
Set
中两个NaN
是相等的1
2let s = new Set([NaN, NaN]);
s // => Set { NaN }在
Set
中两个对象总是不相等的,即使它们都是空对象1
2let s = new Set([{}, {}]);
s // => Set { {}, {} }如果是相同的引用则算作重复
1
2
3let a = {}, b = a;
let s = new Set([a, b]);
s // => Set { {} }
实例的属性
Set.prototype.constructor
返回实例的构造函数。默认情况下是
Set
Set.prototype.size
返回
Set
对象的值的个数1
2let s = new Set([1, 1, 2, 2, 3, 3, 4, 4]);
s.size // => 4
实例的方法
操作方法
Set.prototype.add(value)
在
Set
尾部添加值,返回原Set
;支持链式操作,添加重复的值无效1
2
3
4
5let s = new Set();
s.add(1); // => Set { 1 }
s.add(2).add(3); // => Set { 1, 2, 3 }
s.add(2); // => Set { 1, 2, 3 }向
Set
加入值时不会发生类型转换1
2let s = new Set();
s.add(1).add('1'); // => Set { 1, '1' }Set.prototype.delete(value)
删除
Set
中的某个值,如果存在返回true
,否则返回false
1
2
3let s = new Set([1, 2, 3, 4]);
s.delete(2); // => Set { 1, 3, 4 }
console.log(s.delete(2)); // => falseSet.prototype.has(value)
判断某个值是否在
Set
中,返回一个布尔值1
2
3let s = new Set([1, 2, 3, 4]);
console.log(s.has(2)); // => true
console.log(s.has('2')); // => falseSet.prototype.clear()
清空
Set
中所有值1
2let s = new Set([1, 2, 3, 4]);
s.clear(); // => Set {}
遍历方法
values()
、keys()
、entries()
Set
结构没有键名,只有键值,故values()
和keys()
方法行为一致,返回遍历器对象,按照插入顺序遍历Set
的值;entries()
返回的遍历器同时包含键名和键值,键名用键值代替1
2
3
4
5
6
7
8
9
10
11
12
13
14const s = new Set([1, 'a', '1']);
for (let item of s.keys()) {
console.log(item);
}
// 1 'a' '1'
for (let item of s.values()) {
console.log(item);
}
// 1 'a' '1'
for (let item of s.entries()) {
console.log(item);
}
// [ 1, 1 ] [ 'a', 'a' ] [ '1', '1' ]forEach()
对
Set
的每个值执行某种操作1
2
3const s = new Set([1, 'a', '1']);
s.forEach((value, key) => console.log(value + key));
// 2 aa 11扩展运算符
扩展运算符可以用于
Set
1
2let arr = [1, 1, 2, 2, 3, 3, 4, 4];
arr = [...new Set(arr)]; // => [ 1, 2, 3, 4 ]可以通过将
Set
转换为数组从而使用数组实例的方法,再将数组转回Set
来达到修改的目的1
2let s = new Set([1, 2, 3]);
s = new Set([...s].map(x => x * 2)); // => Set { 2, 4, 6 }
WeakSet
WeakSet
结构与Set
类似,但有两个不同
WeakSet
的成员只能是对象1
2
3
4let ws = new WeakSet();
ws.add(1);
// TypeError: Invalid value used in weak setWeakSet
中的对象都是弱引用,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象是否还存在于WeakSet
中由于这种特性,
WeakSet
无法遍历,可以用于存储DOM节点,而不用担心这些节点从文档移除时会引发内存泄漏
Map
基本概念
Map
是键值对的集合,但是键不一定是字符串,也可以是各种类型的值
Map
本身是一个构造函数,可以用new
生成新的Map
数据结构,可以接受数组或类数组(具有iterable
接口)为参数,其元素为键值对(两个元素的数组),null
会被当做undefined
1 | let m = new Map([ |
实例的属性
Map.prototype.constructor
返回一个函数,它创建了实例的原型。默认是
Map
函数Map.prototype.size
返回Map对象的键/值对的数量
1
2
3
4
5
6let m = new Map([
['name', 'apple'],
['type', 'fruit'],
]);
m.size // => 2
实例的方法
操作方法
Map.prototype.set(key, value)
设置Map中的键值,返回该
Map
对象;如果key
已有值,则会被更新;支持链式操作1
2
3
4
5
6
7let m = new Map([
['name', 'apple'],
['type', 'fruit'],
]);
m.set('price', '$1').set('name', 'banana');
// Map { 'name' => 'banana', 'type' => 'fruit', 'price' => '$1' }需要注意的是,只有对同一个对象的引用,
Map
才将其视为同一个键1
2
3
4
5let key1 = ['a'], key2 = ['a'], key3 = key1;
let m = new Map();
m.set(key1, 1).set(key2, 2).set(key3, 3);
// Map { [ 'a' ] => 3, [ 'a' ] => 2 }如果
Map
的键是简单类型(数字、字符串、布尔值),那么只要两个值严格相等,Map
就将其视为一个键;特别地,NaN
也被视为同一个键1
2
3
4
5
6
7let m = new Map();
m.set(-0, 0).set(+0, 1);
m.set(true, 0).set('true', 1);
m.set(NaN, 0).set(NaN, 1);
console.log(m)
// Map { 0 => 1, true => 0, 'true' => 1, NaN => 1 }Map.prototype.get(key)
返回键对应的值,如果不存在,则返回
undefined
1
2
3
4
5
6let m = new Map([
['name', 'apple'],
['type', 'fruit'],
]);
m.get('name') // => appleMap.prototype.has(key)
返回一个布尔值,表示
Map
实例是否包含键对应的值1
2
3
4
5
6
7let m = new Map([
['name', 'apple'],
['type', 'fruit'],
]);
m.has('name'); // => true
m.has('price'); // => falseMap.prototype.clear()
移除
Map
的所有键值对,无返回值1
2
3
4
5
6let m = new Map([
['name', 'apple'],
['type', 'fruit'],
]);
m.clear(); // => Map {}Map.prototype.delete(key)
如果
Map
对象中存在该元素,则移除它并返回true
;否则如果该元素不存在则返回false
1
2
3
4
5
6
7
8
9let m = new Map([
['name', 'apple'],
['type', 'fruit'],
]);
m.delete('name'); // => true
m.delete('price'); // => false
console.log(m); // => Map { 'type' => 'fruit' }
遍历方法
Map.prototype.keys()
返回一个新的
Iterator
对象,按插入顺序包含了Map
中每个元素的键1
2
3
4
5
6
7
8
9let m = new Map([
['name', 'apple'],
['type', 'fruit'],
]);
for (let key of m.keys()) {
console.log(key);
}
// name typeMap.prototype.values()
返回一个新的
Iterator
对象,按插入顺序包含了Map
中每个元素的值1
2
3
4
5
6
7
8
9let m = new Map([
['name', 'apple'],
['type', 'fruit'],
]);
for (let value of m.values()) {
console.log(value);
}
// apple fruitMap.prototype.entries()
返回一个新的
Iterator
对象,按插入顺序包含了Map
中每个元素的[key, value]
数组1
2
3
4
5
6
7
8
9let m = new Map([
['name', 'apple'],
['type', 'fruit'],
]);
for (let item of m.entries()) {
console.log(item);
}
// [ 'name', 'apple' ] [ 'type', 'fruit' ]Map.prototype.forEach(callbackFn)
按插入顺序,为
Map
里的每一键值对调用一次callbackFn
函数1
2
3
4
5
6
7
8
9let m = new Map([
['name', 'apple'],
['type', 'fruit'],
]);
m.forEach((key, value) => {
console.log(`${key}: ${value}`)
})
// apple: name fruit: type
与Set
类似,Map
结构也可以使用扩展运算符
1 | const m = new Map([ |
Map与其他数据结构的转换
数组
Map
转变为数组可以使用扩展运算符1
2
3
4
5
6
7let m = new Map([
['name', 'apple'],
['type', 'fruit'],
]);
let arr = [...m];
// [ [ 'name', 'apple' ], [ 'type', 'fruit' ] ]将数组传入
Map
构造函数就可以转为Map
1
2
3
4
5
6
7let arr = [
['name', 'apple'],
['type', 'fruit']
];
let m = new Map(arr);
// Map { 'name' => 'apple', 'type' => 'fruit' }对象
如果
Map
的所有键都是字符串,则可以转为对象1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function mapToObj(map) {
let obj = new Object();
map.forEach((key, value) => {
obj[key] = value;
});
return obj;
}
let m = new Map([
['name', 'apple'],
['type', 'fruit'],
]);
mapToObj(m)
// { apple: 'name', fruit: 'type' }对象也可以转为
Map
1
2
3
4
5
6
7
8
9
10
11
12function objToMap(obj) {
let m = new Map();
for (let key in obj) {
m.set(key, obj[key]);
}
return m;
}
let obj = { apple: 'name', fruit: 'type' };
objToMap(obj)
// Map { 'apple' => 'name', 'fruit' => 'type' }JSON
通过将
Map
转换为数组或对象再转换为JSON
WeakMap
WeakMap
与Map
类似,是一组键值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的
典型的应用场景是:在网页的DOM元素上添加数据时就可以使用WeakMap
结构,当该元素被清除,其所对应的WeakMap
记录就会自动被移除