Bootstrap

Vue reactive简单实现原理

// 当前的依赖函数
let currentEffect;

// 使用依赖的类
class Dep {
    constructor(value) {
        this.deps = new Set();
        this._value = value;
    }

    get value() {
        this.depend()
        return this._value
    }

    set value(val) {
        this._value = val;
        this.notice()
    }

    depend() {
        if (currentEffect) {
            this.deps.add(currentEffect)
        }
    }

    notice() {
        this.deps.forEach(effect => {
            effect()
        })
    }
}

function ref(Raw) {
    const dep = new Dep(Raw)
    return {
        get value() {
            return dep.value
        },
        set value(val) {
            dep.value = val
        }
    }
}

// const dep = new Dep(10);

function effectWatch(effect) {
    currentEffect = effect;
    // 此处只需要调用effect来进行以来收集,目的是读取依赖的值触发get
    effect();
    // dep.depend();
    currentEffect = null;
}

// 全局的响应式map
const targetDeps = new Map()
// 使用map是因为它的键可以是任何数据类型包括对象
function getDep(target, key) {

    let deps = targetDeps.get(target);
    if (!deps) {
        deps = new Map()
        targetDeps.set(target, deps)
    }
    let dep = deps.get(key);
    if (!dep) {
        dep = new Dep(target[key])
        deps.set(key, dep)
    }
    return dep
}

function reactive(Raw) {
    return new Proxy(Raw, {
        get(target, key) {
        //如果拿到的值是一个对象那么就进行递归代理
            if (typeof target[key] === "object") {
                return reactive(target[key])
            }
            const dep = getDep(target, key)
            dep.depend()
            return Reflect.get(target, key)
        },
        set(target, key, value) {
            if (typeof target[key] === "object") {
                return reactive(target[key])
            }
            const dep = getDep(target, key)
            const result = Reflect.set(target, key, value)
            dep.notice()
            return result
        }
    })
}

const obj = {
    zhangsan: {
        age: 10,
        gender: {
            age: 19
        }
    }
}
const user = reactive(obj);
// 使用b、c两个变量
let b, c;
effectWatch(() => {
    b = user.zhangsan.gender.age + 100;
    console.log("b", b)
    c = user.zhangsan.age
    console.log("c", c)
})

// user.zhangsan.gender.age = 200;
user.zhangsan.age = 15
;