1.Set
基本用法
Set是一个构造函数,用来生成Set数据结构,它类似于数组,但是成员的值都是唯一的,没有重复的值,接收一个数组(或类似数组的对象)作为参数,用来初始化。
const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
for (let i of s) {
console.log(i);
}
// 2 3 5 4
// 用途:去除数组的重复成员
[...new Set(array)]
- 向Set加入值时,不会发生类型转换,5和"5"是两个不同的值。
- 在Set内部,两个NaN是相等的。
- 两个对象总是不相等的。
Set实例的属性和方法
属性
- Set.prototype.constructor:构造函数,默认就是Set函数
- Set.prototype.size:返回Set实例的成员总数
方法
操作方法(操作数据):
- add(value):添加某个值,返回Set结构本身
- delete(value):删除某个值,返回一个布尔值,表示删除是否成功
- has(value):返回一个布尔值,表示该值是否为Set的成员
- clear(value):清除所有成员,没有返回值
Array.from方法可以将Set结构转为数组,可以用来去除数组的重复成员。
function dedupe(array) {
return Array.from(new Set(array));
}
dedupe([1, 1, 2, 3]) // [1, 2, 3]
遍历方法(遍历成员):
- keys():返回键名的遍历器
- values():返回键值的遍历器,Set结构没有键名,键名和键值是同一个值
- entries():返回键值对的遍历器
- forEach():使用回调函数遍历每个成员,用于对每个成员执行某种操作,没有返回值,参数依次为键值、键名、集合本身,还可以有第二个参数,表示绑定的this对象
for (let item of set.values()) {//可以写成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
2.WeakSet
含义
与Set类似,也是不重复的值的集合,但是它的成员只能是对象,不能是其他类型的值,其中的对象都是弱引用,如果其他对象都不再引用该对象,那么垃圾回收机制会主动回收该对象所占的内存,不考虑该对象还存在于WeakSet之中,WeakSet适合临时存放一组对象,以及存放跟对象绑定的信息。
- WeakSet不能遍历,因为成员都是弱引用,随时可能消失。
- WeakSet有三个方法:add、delete、has
- WeakSet没有size属性,不能遍历成员
const a = [[1, 2], [3, 4]];
const ws = new WeakSet(a);
// WeakSet {[1, 2], [3, 4]}
3.Map
含义和基本用法
Map数据结构类似于对象,也是键值对的集合,但是键的范围不限于字符串,各种类型的值都可以当做键,是一种更完善的Hash结构实现,作为构造函数,Map也可以接受一个数组作为参数,数组成员是一个个表示键值对的数组。
const map = new Map([
['name', '张三'],
['title', 'Author']
]);
map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"
- 如果对同一个键多次赋值,后面的值将覆盖前面的值。
- 如果读取一个未知的键,返回undefined。
- 只有对同一个对象的引用,Map结构才视为同一个键,set和get方法表面是针对同一个值,实际上是两个值,内存地址是不一样的。
- 同一个值的两个实例,在Map结构中被视为两个键。
- 如果Map的键是一个简单类型的值(数字、字符串、布尔值),0和-0是同一个键,布尔值true和字符串true是两个不同的键,NaN是同一个键。
let map = new Map();
map.set(-0, 123);
map.get(+0) // 123
实例的属性和操作方法
size属性:返回Map结构的成员总数
set(key,value)方法:设置/更新键名key对应的键值为value,然后返回整个Map结构,可以采用链式写法
get(key):读取key对应的键值,找不到返回undefined
has(key):返回布尔值,表示某个键是否在当前Map中
delete(key):返回布尔值,表示是否删除成功
clear():清除所有成员,没有返回值
遍历方法和Set相同,keys()、values()、entries()、forEach()
与其他数据结构的相互转换
- Map转为数组:使用扩展运算符
const myMap = new Map()
.set(true, 7)
.set({foo: 3}, ['abc']);
[...myMap]
// [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]
- 数组转为Map:将数组传入Map构造函数
new Map([
[true, 7],
[{foo: 3}, ['abc']]
])
// Map {
// true => 7,
// Object {foo: 3} => ['abc']
// }
- Map转为对象:所有Map的键都是字符串,则可以转为对象,使用Object.create创建对象,然后循环赋值
function strMapToObj(strMap) {
let obj = Object.create(null);
for (let [k,v] of strMap) {
obj[k] = v;
}
return obj;
}
const myMap = new Map()
.set('yes', true)
.set('no', false);
strMapToObj(myMap)
// { yes: true, no: false }
- 对象转为Map:遍历对象,使用Map的set方法
function objToStrMap(obj) {
let strMap = new Map();
for (let k of Object.keys(obj)) {
strMap.set(k, obj[k]);
}
return strMap;
}
objToStrMap({yes: true, no: false})
// Map {"yes" => true, "no" => false}
- Map转为JSON:Map的键名如果是字符串,则转为对象JSON,如果含有非字符串,则转为数组JSON
//对象JSON
function strMapToJson(strMap) {
return JSON.stringify(strMapToObj(strMap));
}
let myMap = new Map().set('yes', true).set('no', false);
strMapToJson(myMap)
// '{"yes":true,"no":false}'
数组 JSON
function mapToArrayJson(map) {
return JSON.stringify([...map]);
}
let myMap = new Map().set(true, 7).set({foo: 3}, ['abc']);
mapToArrayJson(myMap)
// '[[true,7],[{"foo":3},["abc"]]]'
- JSON转为Map
function jsonToStrMap(jsonStr) {
return objToStrMap(JSON.parse(jsonStr));
}
jsonToStrMap('{"yes": true, "no": false}')
// Map {'yes' => true, 'no' => false}
4.WeakMap
含义
与Map结构类似,也是用于生成键值对的集合,只接受对象作为键名(null除外),不接受其他类型的值作为键名,WeakMap的键名所指向的对象,不计入垃圾回收机制,它没有遍历操作,无法清空。
应用
注册监听事件的listener对象,监听函数放在WeakMap里面,一旦DOM对象消失,和它绑定的监听函数也会消失
const listener = new WeakMap();
listener.set(element1, handler1);
listener.set(element2, handler2);
element1.addEventListener('click', listener.get(element1), false);
element2.addEventListener('click', listener.get(element2), false);
还可以用来部署私有属性。
const _counter = new WeakMap();
const _action = new WeakMap();
class Countdown {
constructor(counter, action) {
_counter.set(this, counter);
_action.set(this, action);
}
dec() {
let counter = _counter.get(this);
if (counter < 1) return;
counter--;
_counter.set(this, counter);
if (counter === 0) {
_action.get(this)();
}
}
}
const c = new Countdown(2, () => console.log('DONE'));
c.dec()
c.dec()
// DONE