// 动态数据
class Dep {
// this指向实例对象
constructor(val) {
this._value = val
this._dep = new Set()
}
// 实例获取value时触发,并且开始收集依赖
get value() {
console.log('----------', this, effect, 'get');
this.addFn()
return this._value
}
// 实例设置value时触发,此时去触发对应实例的依赖
set value(newVal) {
if (newVal === this._value) return
this._value = newVal
this.emitFn()
// console.log(this, 'set');
}
// 收集依赖
addFn() {
effect && this._dep.add(effect)
}
// 触发依赖
emitFn() {
this._dep.forEach(effect => effect && effect())
}
}
// 缓存执行方法
let effect = null
// 监听器--模仿vue3
const watchEffect = (fn) => {
effect = fn
fn() // 立即执行一次
effect = null
}
// 简单数据类型实现响应式监听测试示例
// const simple = new Dep('hello')
// const num = new Dep(11)
// watchEffect(() => {
// console.log(simple.value, num.value, '-----');
// })
// simple.value = 'wo'
// num.value = 22
// 复杂数据类型实现响应式监听实现方法 -- 模仿vue3 reactive
/**
总响应式键值对存储信息 --- allDeps
Map(1) {
{ name: 'lisi', age: 18 } => Map(2) {
'age' => Dep { _value: 18, _dep: Set(0) {} },
'name' => Dep { _value: 'lisi', _dep: Set(0) {} }
}
}
*/
const allDeps = new Map()
const reactive = (obj) => {
return new Proxy(obj, {
get(target, key) {
// 初始化时,把对象整体存起来,后面再次访问该对象时,找到对应存的对象访问
let itemDeps = allDeps.get(target)
if (!itemDeps) {
itemDeps = new Map()
// 把整个对象作为key缓存起来
allDeps.set(target, itemDeps)
}
// obj --- key1 ====> Dep1 key2 ===> Dep2
// 通过劫持对象中的每个属性,从而实现劫持整个对象
// 接着缓存对象内每一个key,对应指向一个Dep实例,相当于创建了一个简单类型的响应数据
let dep = itemDeps.get(key)
if (!dep) {
dep = new Dep(Reflect.get(target, key))
itemDeps.set(key, dep)
}
// 收集实例依赖方法
dep.addFn()
return Reflect.get(target, key)
},
set(target, key, val) {
// 初始化时,把对象整体存起来,后面再次访问该对象时,找到对应存的对象访问
let itemDeps = allDeps.get(target)
if (!itemDeps) {
itemDeps = new Map()
// 把整个对象作为key缓存起来
allDeps.set(target, itemDeps)
}
// obj --- key1 ====> Dep1 key2 ===> Dep2
// 通过劫持对象中的每个属性,从而实现劫持整个对象
// 一个待实现猜想: 只监听整个大对象时,改变大对象中的一个属性,能否也触发监听器?
// 接着缓存对象内每一个key,对应指向一个Dep实例,相当于创建了一个简单类型的响应数据
let dep = itemDeps.get(key)
if (!dep) {
dep = new Dep(Reflect.get(target, key))
itemDeps.set(key, dep)
}
Reflect.set(target, key, val)
// 同步修改响应数据,触发依赖通知函数
dep.value = val
}
})
}
// 复杂响应式数据测试示例
const rea = reactive({
name: 'lisi',
age: 18
})
watchEffect(() => {
console.log(rea.name, 'reaw');
})
rea.name = "11"
模拟vue响应数据和监听
于 2023-10-25 15:00:30 首次发布