vue.js设计与实现(阅读)-五(浅响应和深响应-浅只读和深只读)

160 阅读2分钟

判断加入两个参数用来 控制响应的深度( isShallow)和 读取属性的深度 (isReadonly)

isShallow 用来控制响应数据的深度,在代理get方法中,该参数默认为false,表示深响应,如是传入参数true,则表示用户需要浅响应,若是true,直接返回第一层代理值,若是false,则默认情况下,递归循环属性嵌套即可

isReadonly 用来控制用户只读取操作的深度,默认为false,表示用户默认情况下不是只读,表示允许修改等操作,若是传入true,则表示只允许用户只读,两者结合,在只读的基础上加入响应深度,则表示只读的响应深度,仅此而已

  • 浅响应和深响应
function createReactive(obj,isShallow=false){
        return new Proxy(obj,{
            get(target,key,receiver){
                if(key === 'raw'){
                    return target
                }
                const res = Reflect.get(target,key,receiver)
                track(target,key)
                // 如果是浅响应,直接返回原始值
                if(isShallow){
                    return res
                }
                // 深响应
                if(typeof res==='object'&&res!==null){
                    return createReactive(res)
                }
                return res
            },
            set(target,key,newVal,receiver){
                const oldValue = target[key]
                const type = Object.prototype.hasOwnProperty.call(target,key)?'SET':'ADD'
                const res = Reflect.set(target,key,newVal,receiver)
                if(target===receiver.raw){
                    if(oldValue!==newVal&&(oldValue===oldValue||newVal===newVal)){
                        trigger(target,key,type)
                    }
                }
                return res
            },
            ownKeys(target){
                track(target,ITERATE_KEY)
                return Reflect.ownKeys(target)
            },
            deleteProperty(target,key){
                const hadKey = Object.prototype.hasOwnProperty.call(target,key)
                const res = Reflect.deleteProperty(target,key)
                if(hadKey&&res){
                    trigger(target,key,'DELETE')
                }
                return res
            }
        })
    }

调用测试:

 // 深响应
    function reactive(obj){
        return createReactive(obj)
    }
    // 浅响应
    function shallowReactive(obj){
        return createReactive(obj,true)
    }

    const obj = shallowReactive({foo:{bar:1}})
    effect(()=>{
        console.log(obj.foo.bar)
    })
    
    // 修改obj.foo.bar的值,并不能触发响应,复函数不执行
    // obj.foo.bar=2
  • 只读和浅只读 实现:
function createReactive(obj,isShallow=false,isReadonly=false){
        return new Proxy(obj,{
            get(target,key,receiver){
                if(key === 'raw'){
                    return target
                }
                const res = Reflect.get(target,key,receiver)
                // 非只读的时候才需要建立响应关系
                if(!isReadonly){
                    track(target,key)
                }
                // 如果是浅响应,直接返回原始值
                if(isShallow){
                    return res
                }
                // 深响应
                if(typeof res==='object'&&res!==null){
                    // 如果深只读,需要再次调用浅只读再进行包装
                    return isReadonly?readonly(res): createReactive(res)
                }
                return res
            },
            set(target,key,newVal,receiver){
                if(isReadonly){
                    console.log(`属性${key}是只读的`)
                    return true
                }
                const oldValue = target[key]
                const type = Object.prototype.hasOwnProperty.call(target,key)?'SET':'ADD'
                const res = Reflect.set(target,key,newVal,receiver)
                if(target===receiver.raw){
                    if(oldValue!==newVal&&(oldValue===oldValue||newVal===newVal)){
                        trigger(target,key,type)
                    }
                }
                return res
            },
            ownKeys(target){
                track(target,ITERATE_KEY)
                return Reflect.ownKeys(target)
            },
            deleteProperty(target,key){
                if(isReadonly){
                    console.log(`属性${key}是只读的`)
                    return true
                }
                const hadKey = Object.prototype.hasOwnProperty.call(target,key)
                const res = Reflect.deleteProperty(target,key)
                if(hadKey&&res){
                    trigger(target,key,'DELETE')
                }
                return res
            }
        })
    }

调用:

 // 深只读
    function readonly(obj){
        return createReactive(obj,false,true)
    }

    // 浅只读:只能读到第一层
    function shallowReadonly(obj){
        return createReactive(obj,true,true)
    }
    const obj = shallowReadonly({foo:{bar:1}})
    effect(()=>{
        console.log(obj.foo.bar)
    })
    obj.foo.bar = 2