WeakMap简介
作为es6一种新的数据结构,他是一种键值对的集合。与Map最大的区别有两个
1. 是其中的键必须是对象或非全局注册的符号。
全局注册的符号
const s1 = Symbol.for('mySymbol')
非全局注册的符号
const s1 = Symbol('mySymbol')
了解Symbol.for
2. 不会创建对它的键的强引用
不会像变量一样随着作用域的销毁而被清除就是强引用
一个对象作为 WeakMap 的键存在,不会阻止该对象被垃圾回收。当该对象的所有强引用都销毁时,该对象的弱引用也随之自动被清除。那么就会在 WeakMap 中相应的值便成为了进行垃圾回收的候选对象,只要它们没有其他的引用存在。
我们使用Map做下简单对比
let map = new Map()
let key = { name: 1 }
map.set(key, '我的键是一个对象')
key = null
setTimeout(() => {
console.log(map) //无论延迟多久,map里面的键值对都会存在
}, 10000);
let wMap = new WeakMap()
let key2 = { name: 1 }
wMap.set(key2, '我的键是一个对象')
key2 = null
setTimeout(() => {
console.log(wMap) //会被浏览器的回收机制回收(测试edge浏览器十秒回收),WeakMap里面的键值对已经清空。
}, 10000);
可以看到在使用Map创建的对象里,即使key对象和map对象已经没有任何地方使用,甚至我们将key设置为了null,但是在内存里,{name: 1}依旧会存在,因为在map对象中的键依旧对它有着强引用的关系。
而我们使用的WeakMap创建的对象,当我们将key2设置为bull后,因为wMap的键是弱引用的关系,所以该键值会直接被垃圾回收机制回收,该键值对会直接被清除。
常见方法
delete
删除任何与 key 关联的值。删除之后,WeakMap.prototype.has(key) 将会返回 false。
get
返回与 key 关联的值,如果不存在则返回 undefined。
has
返回一个布尔值,断言某个值是否已经与 WeakMap 对象中的 key 关联。
set
给 WeakMap 对象中的 key 设置 value。返回该 WeakMap 对象。
应用场景
-
Vue 3 的响应式系统使用了 Proxy 对象来拦截对响应式对象的访问,然后在内部使用 WeakMap 来跟踪对象与其对应的副作用(例如渲染函数或侦听器)。这样,当响应式对象发生变化时,Vue 3 可以根据这些依赖关系自动进行更新。
通过 WeakMap,Vue 3 实现了一种弱引用关系,这意味着如果一个对象不再被其他地方引用,它将被垃圾回收机制自动回收,同时也会自动清理相应的依赖关系。 -
WeakMap还常常被用来保存对象的私有数据。这是因为WeakMap的键不可遍历,所以我们可以利用这个特性来存储一些只有特定代码能够访问的数据。
上面是一个人们经常拿来说明WeakMap应用场景的一个方法,但实际上描述并不完全正确。
实际上WeakMap 方式定义私有属性的主要作用是保护属性的名称,防止和其他实例的同名属性发生冲突。但不能保证属性的值不被修改。使用getPrivateVal方法外还可以直接使用privateData.get(obj)的方式进行访问甚至对值进行修改。
- 曾经看到使用WeakMap进行栈的模拟实现
let Stack = (function(){
let items = new WeakMap()
class Stack {
constructor () {
items.set(this, [])
}
pop () { // 出栈
return items.get(this).pop()
}
push (v) { // 入栈
items.get(this).push(v)
}
peek () { // 获取当前栈顶
return items.get(this)[items.get(this).length - 1]
}
size () { // 栈长度
return items.get(this).length
}
isEmpty () { // 栈是否为空
return items.get(this).length === 0
}
clear () { // 清空栈
items.get(this).length = 0
}
}
return Stack
})()