美文网首页
Set和Map数据结构介绍及使用场景分析

Set和Map数据结构介绍及使用场景分析

作者: Mr无愧于心 | 来源:发表于2020-06-10 21:40 被阅读0次

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的区别:

  1. WeakSet 的成员只能是对象,而不能是其他类型的值
const ws = new WeakSet();
ws.add(1)
//以上代码会报错
ws.add({a:1})

  1. WeakSet对象只有add delete has 没有clear方法和size属性
ws.size  // undefined
ws.clear() //抛错
  1. 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结构

介绍:
  1. 它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括null、undefined、对象、数组、正则。。。)都可以当作键
  2. 同一个键多次赋值,后面的值将覆盖前面的值
  3. 只有对同一个对象的引用,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结构类似,也是用于生成键值对的集合。
区别

  1. WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名
  2. WeakMap的键名所指向的对象,不计入垃圾回收机制(类似于WeakSet)
  3. 是没有遍历操作(即没有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
应用(vue3.0数据劫持实现)

vue3.0中的数据监听原理简析

相关文章

网友评论

      本文标题:Set和Map数据结构介绍及使用场景分析

      本文链接:https://www.haomeiwen.com/subject/gtsutktx.html