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
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
。
// 代码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
,是实例的弱引用,所以如果删除实例,它们也就随之消失,不会造成内存泄漏。