vue3相比于vue2有了明显的性能提升,而最直接的就是从Object.defineProperty换成了proxy做数据劫持,而effect是响应式系统的核心,响应式系统又是vue3中的核心。

最基本的响应式就是我改变一个值,另一个值也自动做出变化。
image.png image.png

此时我们执行一下文件会看到达到了我们想要的目的。当然这并不是我们最终想要的,我们看一下vue3是如何做的。
在vue3中reactivity可以作为一个单独的模块下载。

image.png

image.png

effect函数执行了两次,在第一次传入匿名函数的时候执行了一次 在之后a变量的值发生变化的时候又执行了一次。

现在我们自己来实现一个响应式系统。
响应式最重要的就是收集依赖和触发依赖。
1.创建一个类用来收集和触发依赖
image.png

2.在声明变量时触发收集操作
image.png

这时候就和vue3中的ref很像了。现在可以优化一下。将在收集依赖时手动调用depend方法改为在get方法中调用,在变量重新赋值时手动调用notice方法改为在set中调用。
image.png

3.创建一个reactive函数,return一个Proxy对象
image.png

在Proxy中使用get来拦截取值行为并return出对应结果。这里我们使用的是ES6新的Reflect函数。相关文档点击这里,总之Reflect.get(target,key)相当于target[key]。

4.创建全局map用于存储所有的对象与依赖关系
image.png

5.设置set方法拦截赋值行为并触发依赖

6.使用effectWatch方法保存依赖
image.png

这就完成了一个基本的reactive方法,实现了响应式关系。
全部代码:

// let a = 10;
// let b;
// update()
// function update() {
//     b = a + 10;
//     console.log(b)
// }
// a = 20;
// update();

// vue3的reactivity模块
// const { reactive, effect } = require("@vue/reactivity");
// let a = reactive({
//     value: 10,
// });
// let b;
// effect(() => {
//     b = a.value + 10;
//     console.log(b);
// });
// a.value = 20;

// 响应式库
let currentEffect; // 全局依赖
class Dep {
    constructor(val) {
        this.effects = new Set(); // 依赖列表
        this._val = val;
    }
    get value() {
        this.depend();
        return this._val;
    }
    set value(newVal) {
        this._val = newVal
        this.notice()
    }
    // 收集依赖
    depend() {
        if (currentEffect) this.effects.add(currentEffect)
    }
    // 触发依赖
    notice() {
        this.effects.forEach((effect) => {
            effect()
        })
    }
}
// 收集依赖
function effectWatch(effect) {
    currentEffect = effect;
    // 绑定依赖时先触发一次依赖
    effect();
    currentEffect = null;
}
// const dep = new Dep(10)
// let b;
// effectWatch(() => {
//     b = dep.value + 10;
//     console.log(b)
// })

// dep.value = 20;



// vue3 proxy
const targetMap = new Map(); // 存储所有的依赖映射关系

function getDepta(target, key) {
    let depsMap = targetMap.get(target) // 获取对象的所有依赖
    if (!depsMap) {
        depsMap = new Map()
        targetMap.set(target, depsMap)
    }
    let dep = depsMap.get(key) // 获取对应key的所有依赖
    if (!dep) {
        dep = new Dep();
        depsMap.set(key, dep)
    }
    return dep;
}

function reactive(obj) {
    return new Proxy(obj, {
        get(target, key) {
            const dep = getDepta(target, key);
            dep.depend() // 收集依赖
            return Reflect.get(target, key)
        },
        set(target, key, value) {
            const dep = getDepta(target, key);
            const relust = Reflect.set(target, key, value)
            // 触发依赖
            dep.notice();
            return relust;
        }
    })
}
const user = reactive({
    age: 19,
    aaa: 30
})
let b, c;
effectWatch(() => {
    console.log('reactive')
    b = user.age + 10
    console.log(b)
})
effectWatch(() => {
    console.log('reactive1111')
    c = user.aaa - 5
    console.log(c)
})
user.age = 20
user.aaa = 20

proudlx
22 声望1 粉丝