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中找到依赖,并进行依赖事件触发