1. Set结构
特征介绍:
1. 类似于数组,没有重复的值
2. 本身是一个构造函数
3. 可以接受一个iterable对象(数组、类数组、字符串...)
4. 有序
5. 键值相等
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
// 去除数组的重复成员(特例: 两个NaN会认为是重复,===判断相等)
[...new Set([1,2,1,'2',NaN,{},NaN,{},4])]
// [1, 2, "2", NaN, {…}, {…}, 4]
// 字符串去重
[...new Set('ababbc')].join('')
// "abc"
属性和方法
size、add()、delete()、has()、clear()
let s=new Set([1,2,3,2]);
s.size //3 相当于数组的length,去重后的结果
s.add(4) //添加一个值,返回 Set 结构本身 可以链式调用
s.delete(2) //true 删除某个值,返回一个布尔值,表示删除是否成功。
s.has(2) //false 返回一个布尔值,表示该值是否为Set的成员
s.clear() // 清除所有成员,没有返回值
遍历 (键值相等)
keys()、values()、entries()、forEach()
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"]
for (let x of set) {
console.log(x);
}
// red
// green
// blue
let set = new Set([1, 4, 9]);
set.forEach((value, key) => console.log(key + ' : ' + value))
// 1 : 1
// 4 : 4
// 9 : 9
使用
数组去重
let arr = [3, 5, 2, 2, 5, 5];
let unique = [...new Set(arr)];//使用...
let unique2 = Array.from(new Set(arr));//使用Array.from()
并集
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
// 并集
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}
交集
let intersect = new Set([...a].filter(x => b.has(x)));
// set {2, 3}
2. WeakSet
WeakSet 结构与 Set 类似,也是不重复的值的集合。
它与 Se的区别:
- WeakSet 的成员只能是对象,而不能是其他类型的值
const ws = new WeakSet();
ws.add(1)
//以上代码会报错
ws.add({a:1})
- WeakSet对象只有add delete has 没有clear方法和size属性
ws.size // undefined
ws.clear() //抛错
- WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。
只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失
const ws = new WeakSet();
let obj1={a:1};
let obj2={b:1};
ws.add(obj1);
ws.add(obj2);
obj2=null;
console.log(ws.has(obj1)) // true
console.log(ws.has(obj2)) // false 引用被释放调了
console.log(ws)
//ws引用中只有{a:1}
//删除obj2引用的时候,不用考虑ws对象,页不用考虑内存泄漏
image.png
3. Map结构
介绍:
- 它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括null、undefined、对象、数组、正则。。。)都可以当作键。
- 同一个键多次赋值,后面的值将覆盖前面的值
- 只有对同一个对象的引用,Map 结构才将其视为同一个键(Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。)
const m = new Map();
const o = {p: 'Hello World'};
m.set(o, 'content')
m.get(o) // "content"
m.has(o) // true
m.delete(o) // true
m.has(o) // false
作为构造函数,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"
// Map构造函数接受数组作为参数,实际上执行的是下面的算法。
const items = [
['name', '张三'],
['title', 'Author']
];
const map = new Map();
items.forEach(
//二级数组的第0个值作为key,第一个值作为value
([key, value]) => map.set(key, value)
);
属性和方法
size、set(key,value)、 get(key)、 has(key)、 delete(key)、 clear()
const map = new Map([
['name', '张三'],
['title', 'Author']
]);
let obj={a:1}
map.size // 2
map.set(obj,10)
//0: {"name" => "张三"}
//1: {"title" => "Author"}
//2: {Object => 10}
map.get(obj) // 10
map.has(obj) // true
map.size // 3
map.delete(obj) // true
map.clear() // undefined
console.log(map) // {}
遍历(map也是有顺序的)
keys()、values()、entries()、forEach()
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.forEach(function(value, key, map) {
console.log("Key: %s, Value: %s", key, value);
});
应用(if...else...的优雅写法)
复杂的判断处理,使用if...else
const onButtonClick = (status,identity)=>{
if(identity == 'guest'){
if(status == 1){
//do sth
}else if(status == 2){
//do sth
}else if(status == 3){
//do sth
}else if(status == 4){
//do sth
}else if(status == 5){
//do sth
}else {
//do sth
}
}else if(identity == 'master') {
if(status == 1){
//do sth
}else if(status == 2){
//do sth
}else if(status == 3){
//do sth
}else if(status == 4){
//do sth
}else if(status == 5){
//do sth
}else {
//do sth
}
}
}
升级为switch-case,还是比较麻烦的
const onButtonClick = (status, identity)=>{
if(identity == 'guest'){
switch (status){
case 1:
//do sth
break
case 2:
//do sth
break
//......
default:
//do sth
break
}
}else{
switch (status){
case 1:
//do sth
break
case 2:
//do sth
break
//......
default:
//do sth
break
}
}
}
升级为map写法(也可以用object对象定义actions,效果一样)
const actions = new Map([
['guest_1', ()=>{/*do sth*/}],
['guest_2', ()=>{/*do sth*/}],
['guest_3', ()=>{/*do sth*/}],
['guest_4', ()=>{/*do sth*/}],
['guest_5', ()=>{/*do sth*/}],
['master_1', ()=>{/*do sth*/}],
['master_2', ()=>{/*do sth*/}],
['master_3', ()=>{/*do sth*/}],
['master_4', ()=>{/*do sth*/}],
['master_5', ()=>{/*do sth*/}],
['default', ()=>{/*do sth*/}],
])
const onButtonClick = (identity,status)=>{
let action = actions.get(`${identity}_${status}`) || actions.get('default')
action.call(this)
}
发挥map的特性(用对象作为key,适用于多元判断)
const actions = new Map([
[{identity:'guest',status:1},()=>{/*do sth*/}],
[{identity:'guest',status:2},()=>{/*do sth*/}],
//...
])
const onButtonClick = (identity,status)=>{
let action = [...actions].filter(([key,value])=>(key.identity == identity && key.status == status))
action.forEach(([key,value])=>value.call(this))
}
如果存在有些状态对应的处理方式是一样的,那么map对象会显得有些啰嗦
这里可以使用正则类型数据作为map的key
const actions = ()=>{
const functionA = ()=>{console.log('a')}
const functionB = ()=>{console.log('b')}
const functionC = ()=>{console.log('c')};
const functionD = ()=>{console.log('d')}
return new Map([
[/^guest_[1|4|6]$/,functionA],
[/^guest_[2|3|5]$/,functionB],
[/^master_[1-4]$/,functionC],
[/^master_[5-7]$/,functionD],
//...
])
}
const ac=(identity,status)=>{
let action = [...actions()].filter(([key,value])=>(key.test(`${identity}_${status}`)))
action.forEach(([key,value])=>value.call(this))
}
ac('guest',2)// b
ac('guest',1)// a
ac('master',2)// c
ac('master',7)// d
---------转自JavaScript 复杂判断的更优雅写法--------
4. WeakMap
WeakMap结构与Map结构类似,也是用于生成键值对的集合。
区别
- WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名
- WeakMap的键名所指向的对象,不计入垃圾回收机制(类似于WeakSet)
- 是没有遍历操作(即没有keys()、values()和entries()方法),也没有size属性
const wm=new WeakMap();
let list=[1,2,3];
let val=[4,5];
wm.set(list,val);
list=null;
wm.get(list);// undefined