set数据结构:
1.去重&&使用...运算符:
var set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]
2.Set可以很容易地实现并集(Union)、交集(Intersect)和差集(Difference)
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}
// 差集
let difference = new Set([...a].filter(x => !b.has(x)));
// Set {1}
3.Array.from
方法可以将 Set
结构转为数组。
WeakSet数据结构:
WeakSet结构与Set类似,也是不重复的值的集合
两个特点:
1.WeakSet的成员只能是对象
2.WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet之中。
关于弱引用,两个应用场景:
1.定义类的时候
const requests = new WeakSet();
class ApiRequest {
constructor() {
requests.add(this);
}
makeRequest() {
if(!request.has(this)) throw new Error("Invalid access");
// do work
}
}
2.创建DOM时候
为了让垃圾回收程序回收元素的内存,可以在这里使用 WeakSet:
const disabledElements = new WeakSet();
const loginButton = document.querySelector('#login'); // 通过加入对应集合,给这个节点打上“禁用”标签 disabledElements.add(loginButton);
这样,只要 WeakSet 中任何元素从 DOM 树中被删除,垃圾回收程序就可以忽略其存在,而立即释放其内存(假设没有其他地方引用这个对象)。
Map数据结构:
它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。如果你需要“键值对”的数据结构,Map比Object更合适。
作为构造函数,Map也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。
var 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实例时,就指定了两个键name
和title
注意,只有对同一个对象的引用,Map结构才将其视为同一个键。这一点要非常小心。
var map = new Map();
map.set(['a'], 555);
map.get(['a']) // undefined
Map结构转为数组结构,比较快速的方法是结合使用扩展运算符(...
)。
let map = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
[...map.keys()]
// [1, 2, 3]
Map数据结构项目应用场景:
在一些 Admin 项目中我们通常都对个人信息进行展示,比如将如下信息展示到页面上。传统方法如下:
HTML代码:
<div class="info-item"> <span>姓名</span> <span>{{info.name}}</span> </div> <div class="info-item"> <span>年龄</span> <span>{{info.age}}</span> </div> <div class="info-item"> <span>性别</span> <span>{{info.sex}}</span> </div> <div class="info-item"> <span>手机号</span> <span>{{info.phone}}</span> </div> <div class="info-item"> <span>家庭住址</span> <span>{{info.address}}</span> </div> <div class="info-item"> <span>家庭住址</span> <span>{{info.duty}}</span> </div>
JS代码:
mounted() { this.info = { name: 'jack', sex: '男', age: '28', phone: '13888888888', address: '广东省广州市', duty: '总经理' } }
我们通过 Map 来改造,将我们需要显示的 label 和 value 存到我们的 Map 后渲染到页面,这样减少了大量的html代码
HTML代码:
<template> <div id="app"> <div class="info-item" v-for="[label, value] in infoMap" :key="value"> <span>{{label}}</span> <span>{{value}}</span> </div> </div> </template>
JS代码:
data: () => ({ info: {}, infoMap: {} }), mounted () { this.info = { name: 'jack', sex: '男', age: '28', phone: '13888888888', address: '广东省广州市', duty: '总经理' } const mapKeys = ['姓名', '性别', '年龄', '电话', '家庭地址', '身份'] const result = new Map() let i = 0 for (const key in this.info) { result.set(mapKeys[i], this.info[key]) i++ } this.infoMap = result }
WeakMap数据结构:
WeakMap
结构与Map
结构基本类似:1.唯一的区别是它只接受对象作为键名(
null
除外),2.不接受其他类型的值作为键名,而且键名所指向的对象,不计入垃圾回收机制。
应用场景1:
var wm = new WeakMap();
var element = document.querySelector(".element");
wm.set(element, "Original");
wm.get(element) // "Original"
element.parentNode.removeChild(element);
element = null;
wm.get(element) // undefined
上面代码中,变量wm
是一个WeakMap
实例,我们将一个DOM
节点element
作为键名,然后销毁这个节点,element
对应的键就自动消失了,再引用这个键名就返回undefined
。
应用场景2:注册监听事件的listener对象很适合用WeakMap来实现
// 代码1
ele1.addEventListener('click', handler1, false);
ele2.addEventListener('click', handler2, false);
// 代码2
const listener = new WeakMap();
listener.set(ele1, handler1);
listener.set(ele2, handler2);
ele1.addEventListener('click', listener.get(ele1), false);
ele2.addEventListener('click', listener.get(ele2), false);
代码2比起代码1的好处是:由于监听函数是放在 WeakMap 里面,则一旦dom对象ele1,ele2消失,与它绑定的监听函数handler1和handler2 也会自动消失
应用场景3:部署私有属性
let _counter = new WeakMap();
let _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)();
}
}
}
let c = new Countdown(2, () => console.log('DONE'));
c.dec()
c.dec()
上面代码中,Countdown类的两个内部属性_counter
和_action
,是实例的弱引用,所以如果删除实例,它们也就随之消失,不会造成内存泄漏。