vue3!
先创建一个类,收集每个对象改变时候要进行响应的函数,上图的叶子节点。
let activeReactive = null
class Depend {
constructor() {
this.reactiveFns= new Set()//创建这个是为了收集依赖,防止重复收集依赖
},
depend() {//给set中添加相关响应函数
if(activeReactive) {
this.reactiveFns.add(activeReactive)
}
},
notify() {//当对象进行修改时候,遍历相关响应函数
this.reactiveFns.forEach(Fn=>Fn())
}
}
封装一个响应函数,将与对象有关的函数放在响应函数里面
function wathchFn (fn) {
activeReactive = fn
fn() //执行传入函数,判断是否与对象属性有关,若有关则加入depend
activeReactive = null
}
封装一个获取depend的函数,如上图
const targetMap = new WeakMap()
function getDepend (target,key) {
let map = targetMap.target
if (!map) {
map = new Map() //新建Map
targetMap.set(target,map) //WeakMap的键必须为对象
}
let depend = map.key
if (!depend) {
depend = new Depend()//新建depend
map.set(key,depend)
}
return depend //创建了一下当前tatget和key下的depend
}
proxy的响应式函数
function reactive(obj) {
return new Proxy(obj, {
get: function(target, key, receiver) {
// 根据target.key获取对应的depend
const depend = getDepend(target, key)
// 给depend对象中添加响应函数
depend.depend()
return Reflect.get(target, key, receiver)
},
set: function(target, key, newValue, receiver) {
Reflect.set(target, key, newValue, receiver)
const depend = getDepend(target, key)
depend.notify()//若进行修则遍历响应函数
}
})
}
结果测试
const infoProxy = reactive({
address: "广州市",
height: 1.88
})
watchFn(() => {
console.log(infoProxy.address)
})
infoProxy.address = "北京市"
const foo = reactive({
name: "foo"
})
watchFn(() => {
console.log(foo.name)
})
foo.name = "bar"
可以理解,响应式原理为:当一个变量有一个初值,另一段代码使用了这个值,那么当我们修改这个值时候,这段代码可以自动重新执行。
需要重新执行的代码可能不止一行,我们可以将这些代码放入一个函数当中,这样我们的问题变成了,当数据发生变化时,自动去执行某一个函数。
当我们将一个函数放入响应函数中,怎样判断这个函数与哪些对象属性的修改有关呢?
我们可以执行传入的函数,当这个函数对对象的某个属性进行获取或修改时候,就会进入proxy的get或者set当中。我们可以在set或者get当中将这个函数加入depend,当对象发生修改时,遍历这个depend。
那我们要如何获取每个对象中每个属性所对应的depend呢?
我们将get或者set中的target和key传入获取depend的函数(getDepend)。从weakmap中获取target对应的map,若没有map的话则新建一个map;再从map中获取key所对应的depend,若没有depend的话则新建一个depend,然后返回这个depend。这样我们就给有响应函数的属性都创建了一个depend