前言
此专栏记录了在准备找工作的时候,收集的一些较好的前端面试题,希望借助这个机会,来和大家一起分享一下,还望大家多多指出我的不足。
在昨天的文章中我们提到过,在vue实际开发存在的一些内存泄漏的场景,想了解的同学可以移步到juejin.cn/post/723302…
今天我们来以此为基础,拓展一下WeakMap与WeakSet
1.什么是WeakMap(弱引用)?
- ES6新增语法,一种集合类型,与Map相比,它的键只能是object或者继承至object的类型(直接受对象作为键),并且它不具备可迭代性,自然的,没有如Map()那样,可以通过entries()方法或者Symbol.iterator属性进行迭代。
- 同Map()一样,WeakMap也拥有set()、has()、get()、delete()这些分别用于添加键值对、查询、获取值、删除键值对的方法
const wm = new WeakMap()
const key1 = {id : 1}
const key2 = {id : 2};
alert(wm.has(key1)) // false
alert(wm.get(key1)) // undefined
wm.set(key1, '好恶发')
.set(key2, '前端菜鸟')
alert(wm.has(key1)) // true
alert(wm.get(key1)) // 好恶发
wm.delete(key2)
alert(wm.has(key1)) // true
alert(wm.has(key2)) // false
- 在映射中用作键和值的对象以及其它“集合”的类型,在自己内容或者属性被修改时,仍然保持不变
const m = new WeakMap()
const objKey = {},
objVal = {},
arrKey = [],
arrVal = [];
m.set(objKey, objVal);
m.set(arrKey, arrVal);
objKey.foo = "foo";
objVal.bar = "bar";
arrKey.push("foo");
arrVal.push("bar");
// 修改键值的属性,并不会影响到它自身内部的映射关系
console.log(m.get(objKey)); // {bar: "bar"}
console.log(m.get(arrKey)); // ["bar"]
console.log(typeof objKey) // object
关于WeakMap的详细情况,可以看看这篇大佬写的文章:juejin.cn/post/684490…
1.1WeakMap与垃圾回收
WeakMap中的Weak表示在弱引用中,它们所设置的键不属于正式的引用,无法阻止垃圾回机制,下面我们来比较一下强弱引用的在垃圾回收机制中的不同
- 强引用
let map = new Map(); // 弱引用
let key = new Object('a')
function fn1() {
map.set(key, 1)
console.log(map.get(key));
}
fn1()
此段代码中,即使fn1()函数执行完毕,局部作用域被销毁,局部变量obj仍然无法被销毁,这是因为map对 key所引用的对象的强引用依旧存在,只有手动释放内存之后,局部变量obj才在下一次的回收中才会被销毁
手动释放内存
map.delete(key)首先删除键值对,解除map对Obj的强引用,key = null解除key对Obj的强引用,此时变量key才会被垃圾回收机制清除,以上两步,少一步都会导致变量key无法被回收。
let map = new Map(); // 弱引用
let key = new Object('a')
function fn1() {
map.set(key, 1)
console.log(map.get(key));
map.delete(key)
key = null
}
fn1()
- 弱引用
释放内存
let wMap = new WeakMap(); // 弱引用
let key = new Object('a')
function fn1() {
wMap.set(key, 1)
console.log(wMap.get(key));
key = null
}
fn1()
- 我们可以观察到,在弱引用的情况下,不需要使用wMap.delete(key)解除wMap对key的弱引用,直接解除掉key对Object的强引用,就可以使得key被回收
2.什么是WeakSet(弱集合)?
- ES6新增语法,一种集合类型,与WeakMap相似,它的值只能是object或者继承至object的类型,尝试使用非对象类型设置值会抛出TypeError,并且它不具备可迭代性,不能如Set()那样,可以通过entries()方法或者Symbol.iterator属性进行迭代。
- 同Set()一样,WeakMap也拥有add()、has()、delete()这些分别用于增加值、查询、删除元素的方法
const ws = new WeakSet();
const val1 = {id : 1}
const val2 = {id : 2}
alert(ws.has(val1)); // false
ws.add(val1)
.add(val2)
alert(ws.has(val1)); // true
alert(ws.has(val2)); // true
ws.delete(val1)
alert(ws.has(val1)); // false
alert(ws.has(val2)); // true
- 可以使用数组初始化弱集合
const val1 = {id : 1}
const val2 = {id : 2}
const val3 = {id : 3}
// 使用数组初始化弱集合
const wsl = new WeakSet([val1, val2, val3])
alert(wsl.has(val1))
alert(wsl.has(val2))
alert(wsl.has(val3))
// 初始化是全有或者全无的操作
// 只要有一个值无效就会抛出错误,导致整个初始化失败
2.1WeakSet与垃圾回收
WeakSet中'Weak'表示弱集合不属于正式的引用,不会阻止垃圾回收
const ws = new WeakSet()
const container = {
val: {}
}
ws.add(container.val)
function() removeRefetence() {
container.val = null
}
- 原理和WeakMap类似,container维持着对Obj的引用,销毁他们之间的引用后,就会摧毁对象值的最后一个引用,垃圾回收即将清理这个值
3.小结
- 在实际开发中使用WeakMap初始化对象,可以使得对象具有自己属性和方法的同时,又降低内存泄漏的风险
- 使用WeakMap和使用WeakSet时,无法使用通过entries()方法或者Symbol.iterator属性进行迭代