vue3 原理中所用到的数据结构

146 阅读2分钟

这几天复习一下vue的一些问题,又又又回到了那个另人头大的环节:原理。vue3的原理真的是看一次忘一次。这篇讲vue3的文章还是挺好的,连接在此:林三心画了8张图,最通俗易懂的Vue3响应式核心原理解析

其实vue3的响应式抽象出来的结构,就如下所示

图片.png 当fn第一次访问obj(此时obj已经被proxy代理了)时,就会被放入指定的set中, 当obj中的值变了,proxy就会通知相应set中的函数再次运行。

再详情描述下数据结构:

  1. targetMap是WeakMap, 只能以对象为key,而值无所值~
  2. depsMap是Map,没什么特别的
  3. set用于放置函数,函数很难传递名字,所以就用set而不用map了。

里面我觉得最核心的是代码,每次忘记了看一看代码就可以想起来。 注: 个人经验来说,deps其实把他当做中文里的依赖,有点难以理解,因为会下意识的想分清依赖和被依赖,结合上面的图来看,个人感觉翻译成“被依赖”更好理解。

const targetMap = new WeakMap()
function track(target, key) {
    // 如果此时activeEffect为null则不执行下面
    // 这里判断是为了避免例如console.log(person.name)而触发track
    // 注:因为console.log(person.name)这种函数不需要响应式!
    if (!activeEffect) return
    let depsMap = targetMap.get(target)
    if (!depsMap) {
        targetMap.set(target, depsMap = new Map())
    }
    let dep = depsMap.get(key)
    if (!dep) {
        depsMap.set(key, dep = new Set())
    }
    dep.add(activeEffect) // 把此时的activeEffect添加进去
}
function trigger(target, key) {
    let depsMap = targetMap.get(target)
    if (depsMap) {
        const dep = depsMap.get(key)
        if (dep) {
            dep.forEach(effect => effect())
        }
    }
}
function reactive(target) {
    const handler = {
        get(target, key, receiver) {
            track(receiver, key) // 访问时收集依赖
            return Reflect.get(target, key, receiver)
        },
        set(target, key, value, receiver) {
            Reflect.set(target, key, value, receiver)
            trigger(receiver, key) // 设值时自动通知更新
        }
    }
    return new Proxy(target, handler)
}
let activeEffect = null
function effect(fn) {
    activeEffect = fn
    activeEffect()
    activeEffect = null
}
function ref(initValue) {
    return reactive({
        value: initValue
    })
}
function computed(fn) {
    const result = ref()
    effect(() => result.value = fn())
    return result
}
// 调用
let num1 = ref(5)
let num2 = ref(8)
let sum1 = computed(() => num1.value * num2.value)
let sum2 = computed(() => sum1.value * 10)
console.log(sum1.value) // 40
console.log(sum2.value) // 400
num1.value = 10
console.log(sum1.value) // 80
console.log(sum2.value) // 800
num2.value = 16

console.log(sum1.value) // 160
console.log(sum2.value) // 1600