浅析Vue3.0响应式原理

自vue3.0发布以来也好几个月了,最近也一直在忙碌手头上的工作,没有时间来学习vue3.0。刚好快要过年了,公司的事情不是很多,这才抽出时间来学习下vue3.0的响应式原理!

回顾Vue2.x 响应式原理

  • 利用观察者模式 + Object.defineProperty ,收集依赖效率较低,对于深层次数据收集不友好
  • 对于复杂类型数据的删除等操作,监听操作实现较为麻烦

Vue3.0响应式原理

  • 使用了Proxy,收集依赖更加的高效,对于深层次数据的收集更加的方便
  • 可以更好的监听数据的新增、删除等操作

Vue3.0响应式原理图

vue3响应式原理

代码实现

	//判断是否是对象
function isObject(obj){
    return typeof obj === 'object' && obj !== null;
}

//创建代理对象
function reactive(target){
    if(!isObject(target)) return target;

    //创建 代理对象 监听规则
    let handler  = {
        get(target,key,reciver){
            //拦截js对象的获取操作
            let res = Reflect.get(...arguments);
            //收集依赖   
            //将effect 和 key 关联起来 不断触发
            track(target,key);
            //如果访问的key  返回是一个对象 递归继续获取 
            return isObject(res)? reactive(res) : res;
        },
        set(target,key,value,reciver){
            let res = Reflect.set(...arguments);
            //触发更新
            trigger(target,key);
            return res;
        },
        deleteProperty(target, key) {
                let res = Reflect.deleteProperty(target, key);
                return res;
            },
    }
    //返回代理对象
    return new Proxy(target,handler);
}

// 创建栈  存储响应式函数
let effectStrack = []
//创建  wekmap  将 响应式函数 和 key 关联   WeakMap( target : Map( key : Set( effectFn ) ) )  基本结构 
let targetMap = new WeakMap();
// 创建响应式函数
function effect(cb){
    const effectFn = () => {
        try{
            //将响应式函数压入栈
            effectStrack.push(effectFn);
            //执行 cb  触发 代理对象的gettter
            return cb();
        }finally{
            //执行完毕后 出栈销毁
            effectStrack.pop();
        }
    }
    //第一次进入  执行一次  一遍 能和 key 建议映射关系
    effectFn();
    return effectFn;
}
//收集依赖
function track(target,key){
    //判断栈中是否有响应式函数
    let effectFn = effectStrack[effectStrack.length - 1];
    if(effectFn){
        //从映射中取出 代理对象的value 如果不存在,建立 关系 
        let depsMap = targetMap.get(target); //wekmap  map 是键值对 结构  但是他的key 可以值对象等类型
        if(!depsMap){
            depsMap = new Map();
            targetMap.set(targetMap,depsMap);
            //此时 数据结构为  WeakMap( target : Map( ) )  map 是键值对 结构
            //再次获取 wekmap的 key 为target对象的value 是否存在 key这个键  如不存在 继续创建
            let deps = depsMap.get(key);
            if(!deps){
                deps = new Set();
                depsMap.set(key,deps);
                //判断 set中是否 有响应函数 没有 继续创建 set 是 值结构
                if( !deps.has(effectFn) ){
                    deps.add(effectFn);
                    //到这里结构建立完毕
                    //WeakMap( target : Map( key : Set( effectFn ) ) )
                }
            } 
        }
    }
}
//触发依赖
function trigger(target,key){
    //直接获取set集合
    let depsMap = targetMap.get(targetMap);
    if(depsMap){
        let deps = depsMap.get(key)
        deps.forEach( effect => {
            effect();
        } )
    }
}

let obj = reactive({
    name:'张三'
})
effect( () => {
    document.body.innerHTML = obj.name;
})
setInterval(() => {
    obj.name = '我也曾经是一个单纯、善良的少年...'+Math.random();
},1000)

###补充
这里简单实现以下,还有许多漏铜,比如说 还需要判断 一个对象被代理多次 等问题,欢迎补充。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值