实现 proxyRefs
主要思路
proxyRefs: 在vue3中,当return的值里面还有 ref 类型数据的时候,此时可以不经过.value 就可以直接获取到里面的值。(具体例子看单测)
实现get逻辑:很简单,判断当前对象属性值是否是ref类型,如果是直接返回ref.value(那么在外面就不用通过.value 去取值了)。如果不是ref类型,那么更简单了,说明要么是reactive类型要么是基本数据类型,直接返回本身即可。
实现set逻辑:如果不需要通过.value去赋值的话,那么也是直接在内部通过target[key].value = value就好了。 但这里需要考虑外部传进来的新值是否是ref类型,如果不是的话,可以使用 target[key].value = value 进行赋值。如果外部传进来的值是ref类型,那么直接赋值即可就不需要.value啦!(也就是 target[key] = value)
代码
export function proxyRefs(objectWithRefs) {
return new Proxy(objectWithRefs, {
get(target, key) {
// get : 如果是 ref 那么返回ref.value 否则 返回 value本身(基本数据类型)
return unRef(Reflect.get(target, key))
},
set(target, key, value) {
// 判断 当前对象属性值 和 传入的值 是否是ref
if (isRef(target[key]) && !isRef(value)) {
return (target[key].value = value)
} else {
return Reflect.set(target, key, value)
}
}
})
}
// isRef 和 unRef
export function isRef(ref) {
return !!ref._v_isRef // 如果是ref那么自然会返回自己身上的_v_isRef属性值,如果不是的话那么会返回undefined 为了返回布尔值在前面加上!!
}
// unRef: 我愿称之为,蜕去外壳,直接返回内部值
export function unRef(ref) {
return isRef(ref) ? ref.value : ref // 如果是ref 返回 ref.value 否则 返回 value本身
}
单元测试
it("proxyRefs", () => {
const user = {
age: ref(1),
name: "zhangsan",
}
const proxyUser = proxyRefs(user)
// get
expect(user.age.value).toBe(1)
expect(proxyUser.name).toBe("zhangsan")
expect(proxyUser.age).toBe(1) // expect(proxyUser.age.value).toBe(1) 省去了value的操作
// set
proxyUser.age = 20
expect(proxyUser.age).toBe(20)
expect(user.age.value).toBe(20)
proxyUser.age = ref(20)
expect(proxyUser.age).toBe(20)
expect(user.age.value).toBe(20)
})