vue3响应式原理


// 保存当前要收集的函数
let activeReactiveFn = null

// 每个响应式数据都需要的依赖
class Depend {
  constructor() {
    // 把搜集到的函数放在一个Set里,可以去除重复的函数
    this.collect = new Set()
  }
  // 添加依赖
  addDepend() {
    if(activeReactiveFn) {
      this.collect.add(activeReactiveFn)
    }
  }
  // 当给响应式数据赋值时,将收集的函数依次执行
  notify() {
    this.collect.forEach(fn => {
      fn()
    })
  }
}

// 需要被收集的函数都需要watch一下,内部会根据取值自动分配给自己的Depend
function watch(fn) {
  activeReactiveFn = fn
  fn()
  activeReactiveFn = null
}

// 将普通对象设置一个代理
function reactive(obj) {
  return new Proxy(obj,{
    get(target,key,receiver) {
      const depend = getDepend(target,key)
      // 搜集依赖
      depend.addDepend()
      return Reflect.get(target,key,receiver)
    },
    set(target,key,newValue,receiver) {
      const depend = getDepend(target,key)
      // 当数据变化时,执行依赖
      depend.notify()
      Reflect.set(target,key,newValue,receiver)
    }
  })
}

const targetMap = new WeakMap()
// 根据传过来的对象和key,获取对应的Depend
function getDepend(target,key) {
  let map = targetMap.get(target)
  if(!map) {
    map = new Map()
    targetMap.set(target,map)
  }
  let depend = map.get(key)
  if(!depend) {
    depend = new Depend()
    map.set(key,depend)
  }
  return depend
}

const obj = {
  name:'liuqi',
  age:18
}

const objProxy = reactive(obj)

function consoleObjName() {
  console.log('consoleObjName',objProxy.name)
}

function consoleObjAge() {
  console.log('consoleObjAge',objProxy.age,objProxy.name)
}

watch(consoleObjName)
watch(consoleObjAge)

objProxy.name = 'why'
// objProxy.age = 20


posted @ 2022-03-18 09:41  coderlq  阅读(54)  评论(0)    收藏  举报