Vue中响应式(拿reactive举例)实现其实是一系列的依赖收集,使用Proxy对传入的对象进行代理监听,返回处理好的代理对象。
//对象的响应式原理
class Depend {
static activeReactiveFn = null
static targetMap = new WeakMap()
constructor() {
this.reactiveFns = new Set()
}
//封装一个获取depend的函数
static getDepend(target, key) {
//根据target对象获取map的过程
let map = Depend.targetMap.get(target)
if (!map) {
map = new Map()
Depend.targetMap.set(target, map)
}
//根据key获取depend对象
let depend = map.get(key)
if (!depend) {
depend = new Depend()
map.set(key, depend)
}
return depend
}
depend() {
if (Depend.activeReactiveFn) {
this.reactiveFns.add(Depend.activeReactiveFn)
}
}
notify() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
//封装一个响应式函数
function watchFn(fn) {
Depend.activeReactiveFn = fn
fn()
Depend.activeReactiveFn = null;
}
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
const dep = Depend.getDepend(target, key)
dep.depend()
return Reflect.get(target, key, receiver)
},
set(target, key, newValue, receiver) {
Reflect.set(target, key, newValue, receiver)
const dep = Depend.getDepend(target, key)
dep.notify()
},
})
}
//对象的响应式
const obj = reactive({
name: 'kano',
age: 18
})
const foo = reactive({
bar: 111
})
watchFn(() => {
console.log('obj.name, obj.age---', obj.name, obj.age);
})
watchFn(() => {
console.log('obj.age---', obj.age);
})
watchFn(() => {
console.log('foo.bar---', foo.bar);
})
// objProxy.name = 'sadada'
obj.age = 999
foo.bar = 'ds'
getDepend 实际上设置了一个依赖树,如图所示:
obj对应一个weakMap,通过读取weakMap的key(目标对象),获取到对应的属性map,再从属性map中找到依赖,并进行依赖事件触发