判断加入两个参数用来 控制响应的深度( 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