vue3.0 响应式原理

function isObject(target) {
    return typeof target === 'object' && target !== null
}
function hasOwn(target, key) {
    return Reflect.has(target, key)
}
let toProxy = new WeakMap()  //  存储 源对象 -> 代理对象
let toRaw = new WeakMap() // 储存 代理对象 -> 源对象 
let effectStacks = []  // 储存 effect
function reactive(target) {
    // 创建代理对象 并返回
    let proxy = creatReactiveObject(target)
    return proxy
}
function creatReactiveObject(target) {
    if (!isObject(target)) return target
    // 判断是否是代理过的对象,或者是代理对象
    let proxy = toProxy.get(target)
    if (proxy) return proxy
    if (toRaw.has(target)) return target
    let handler = {
        get(target, key, receiver) {
            let res = Reflect.get(target, key, receiver)
            track(target, key)
            // 递归,如果res是对象 则继续代理
            return reactive(res)
        },
        set(target, key, value, receiver) {
            // 无效修改,直接返回
            if (hasOwn(target, key) && target[key] === value) return false
            let res = Reflect.set(target, key, value, receiver)
            trigger(target,key)
            return res
        },
        deleteProperty(target, key) {
            let res = Reflect.deleteProperty(target, key)
            console.log('deleteProperty');
            return res
        }
    }
    let observed = new Proxy(target, handler)
    toProxy.set(target, observed)
    toRaw.set(observed, target)
    return observed
}
/*
    {
        target: {
            key: new set
        }
    }    
*/
let targetsMap = new WeakMap() // targetsMap 类似上述结构
// 动态收集依赖
function track(target, key) {
    let effect = effectStacks[effectStacks.length - 1]
    if(effect) {
        let depsMap = targetsMap.get(target)
        if(!depsMap) targetsMap.set(target, depsMap = new Map)
        let deps = depsMap.get(key)
        if(!deps) depsMap.set(key, deps = new Set)
        if(!deps.has(effect)) deps.add(effect)
    }
}
// 触发更新
function trigger(target, key) {
    let depsMap = targetsMap.get(target)
    if(depsMap) {
        let deps = depsMap.get(key)
        if(deps) {
            deps.forEach(effect => {
                effect()
            })
        }
    }
}
function effect(fn) {
    let effect = createEffect(fn)
    // 第一次 立即执行
    effect()
}
function createEffect(fn) {
    let effect = function () {
        run(effect, fn)
    }
    return effect
}
function run(effect, fn) {
    // 1.将effect 加入栈中,以便依赖收集 
    effectStacks.push(effect)
    // 2 执行fn,进行依赖收集
    fn()
    // 3 收集完毕,出栈
    effectStacks.pop()
}

let obj = {
    name: 'xx',
    deepObj: {
        a: 1
    },
    arr: [1, 2, 3]
}

let proxy = reactive(obj)
effect(() => {
    console.log(proxy.name);
})
effect(() => {
    console.log(proxy.name);
})
proxy.name = 'yy'

posted @ 2021-07-06 14:18  有点油  阅读(75)  评论(0)    收藏  举报