• vue3响应式系统



    其实就是vue.js设计与实现的读书笔记()

    前置知识

    Proxy

    Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义。
    Proxy.get

    get(target, propKey, receiver)
    
    • 1
    • target -目标对象
    • propKey -属性名
    • receiver -proxy实例本身
    let target={
        name:"name",
        get alias(){
            console.log("----",this)//这个this绑定的就是reflect的receiver
            return this.name
        }
    }
    
    const proxy=new Proxy(target,{
        get(target,key,receiver){
            console.log(key)
            console.log("receiver",receiver)
           return Reflect.get(target,key,receiver)
        }
    })
    proxy.alias
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    请添加图片描述

    Reflect

    总的来说就是将Object上面一些方法,转成语言的方法,写得更合理一点。一般与Proxy搭配使用

    Reflect.get(target, propertyKey[, receiver])
    
    • 1
    • target -目标对象
    • propKey -属性名
    • receiver -如果target对象中指定了getter,receiver则为getter调用时的this值。

    实现reactive

    初步实现
    export function reactive(target:any){
        if(!isObject(target)){
            return target
        }
        const proxy=new Proxy(target,{
        get(target,key,receiver){
           return Reflect.get(target,key,receiver)
        },
        set(target,key,receiver){
           return Reflect.set(target,key,receiver)
        },
        })
        return proxy
    }
    
    function isObject(obj:any){
        return obj !== null && typeof obj === 'object'
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    但是这样多次代理同一个对象后会多很多不同的代理对象

    (vue3文档)为保证访问代理的一致性,对同一个原始对象调用 reactive() 会总是返回同样的代理对象

    let obj={}
    let reactive1=reactive(obj)
    let reactive2=reactive(obj)
    console.log(reactive1===reactive2)//false
    
    • 1
    • 2
    • 3
    • 4
    引入weakMap 减少冗余代理对象

    于是考虑到使用哈希表来存储,利用哈希表的特性(key-value唯一) 来查询之前有没有存过就创建新对象,存过直接返回之前存过的对象
    使用WeakMap是因为WeakMap的键名所指向的对象,不计入垃圾回收机制(标记清除法的时候WeakMap的键指向不算),便于进行垃圾回收

    let reactiveMap=new WeakMap()
    export function reactive(target:any){
        if(!isObject(target)){
            return target
        }
        if(reactiveMap.get(target)){
            return reactiveMap.get(target)
        }
        const proxy=new Proxy(target,{
        get(target,key,receiver){
           return Reflect.get(target,key,receiver)
        },
        set(target,key,receiver){
           return Reflect.set(target,key,receiver)
        },
        })
        reactiveMap.set(target,proxy)
        return proxy
    }
    
    function isObject(obj:any){
        return obj !== null && typeof obj === 'object'
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    自动解包

    (vue3文档) 对一个已存在的代理对象调用 reactive() 会返回其本身

    这个是利用了当前对象上有没有Proxy产生的getter来判断这个对象是不是已经代理了。
    首先是看这个对象的ReactiveFlags属性,如果这个对象是代理对象的话,它的getter会被拦截,返回true,如果没有就返回underfined

    const ReactiveFlags="_v_IS_REACTIVE"
    export function reactive(target:any){
        if(!isObject(target)){
            return target
        }
        if(reactiveMap.get(target)){
            return reactiveMap.get(target)
        }
        if(target[ReactiveFlags]) return target
        const proxy=new Proxy(target,{
        get(target,key,receiver){
            if(key===ReactiveFlags){
                return true
            }
           return Reflect.get(target,key,receiver)
        },
        set(target,key,receiver){
           return Reflect.set(target,key,receiver)
        },
        })
        reactiveMap.set(target,proxy)
        return proxy
    }
    
    function isObject(obj:any){
        return obj !== null && typeof obj === 'object'
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
  • 相关阅读:
    微信小程序组件所在页面的生命周期
    【问题思考总结】NAT的公有地址怎么转换为私有地址?【MAC地址和IP地址的转换】
    pytorch与深度学习
    【数据分享】1961—2022年全国范围的逐日降水栅格数据
    redis的启动方式
    使用传统方式遍历集合过滤元素和使用流遍历集合过滤元素的区别
    2022年最新Android面试题整理,全网都在看,史上最全面试攻略
    浅拷贝、深拷贝与序列化【初级Java必需理解的概念】
    Grafana----Grafana快速体验
    React的thunk中间件
  • 原文地址:https://blog.csdn.net/neversleepy/article/details/126857366