关注[前端小讴],阅读更多原创技术文章
WeakMap 是 ECMAScript6 的新增特性,是一种新的集合类型,是 Map 的“兄弟”类型,也是 Map 的子集
“weak” 描述的是 JS 垃圾回收程序对待“弱映射”中键的方式
相关代码 →
const wm = new WeakMap()
console.log(wm) // WeakMap {}
// 使用嵌套数组初始化若映射
const key1 = {
id: 1 },
key2 = {
id: 2 },
key3 = {
id: 3 }
const wm1 = new WeakMap([
[key1, 'val1'],
[key2, 'val2'],
[key3, 'val3'],
])
console.log(wm1.get(key1)) // 'val1'
console.log(wm1.get(key2)) // 'val2'
console.log(wm1.get(key3)) // 'val3'
// 只要有一个键无效就会抛出错误,导致初始化失败
const wm2 = new WeakMap([
[key1, 'val1'],
[key2, 'val2'],
[key3, 'val3'],
['key4', 'val4'], // TypeError: Invalid value used as weak map key
])
const key4 = new String('key4')
const wm3 = new WeakMap([
[key1, 'val1'],
[key2, 'val2'],
[key3, 'val3'],
[key4, 'val4'],
])
console.log(wm3.get(key4)) // 'val4'
set()
添加键/值对,使用get()
和has()
进行查询,使用delete()
删除值(同 Map ,但 WeakMap 没有 clear()方法,也没有自带的 size 属性)const wm4 = new WeakMap()
console.log(wm4.size) // undefined,WeakMap不自带size属性
const key5 = {
id: 1 },
key6 = {
id: 2 }
wm4.set(key5, 'Matt').set(key6, 'Frisbie')
console.log(wm4.has(key5)) // true
console.log(wm4.get(key5)) // 'Matt'
wm4.delete(key5) // 删除这个键值对
console.log(wm4.has(key5)) // false
console.log(wm4.get(key5)) // undefined
console.log(wm4.has(key6)) // true
// wm4.clear() // TypeError: wm4.clear is not a function,WeakMap没有clear方法
set()
方法返回弱映射实例,因此可以把多个操作连缀起来,从初始化到添加键/值对(同 Map)const wm5 = new WeakMap().set(key5, 'Matt')
console.log(wm5) // WeakMap { { id: 1 } => 'Matt' }
const wm6 = new WeakMap()
wm6.set({
}, 'val') // 初始化一个新对象作为建,没有指向这个对象的其他引用,代码执行后键和值均会被当作垃圾回收
const wm7 = new WeakMap()
const container = {
key: {
} } // container对象维护着wm7中键的引用
wm7.set(container.key, 'val') // 键和值均不会成为垃圾回收的目标
container.key = null // 切断键对象的引用,键和值才会被垃圾回收
const UserClosure = (() => {
// 用闭包把WeakMap包起来
const wm9 = new WeakMap()
class User {
constructor(id) {
this.idProperty = Symbol('id') // 创建符号
this.setId(id)
}
setId(id) {
this.setPrivate(this.idProperty, id)
}
setPrivate(property, value) {
const privateMembers = wm9.get(this) || {
}
privateMembers[property] = value // { idProperty: Symbol(id): id }
wm9.set(this, privateMembers)
}
getId() {
return this.getPrivate(this.idProperty)
}
getPrivate(property) {
return wm9.get(this)[property] // 获取到id
}
}
return User
})()
const user2 = new UserClosure(123)
console.log(user2) // User { idProperty: Symbol(id) }
console.log(user2.getId()) // 123
user.setId(456)
console.log(user.getId()) // 456
// console.log(wm9) // ReferenceError: wm9 is not defined,拿不到弱映射,无法获取弱映射中对应的值,成功设置私有变量
// 给节点关联元数据,保存在映射中
const m = new Map()
const loginButton = document.querySelector('#login')
m.set(loginButton, {
disabled: true }) // 即使DOM被删除映射仍然存在
// 给节点关联元数据,保存在弱映射中
const wm10 = new WeakMap()
const loginButtin2 = document.querySelector('#login')
wm10.set(loginButton, {
disabled: true }) // DOM被删除(若没有其他地方引用loginButton)弱映射被回收