isRef
isRef和isReactive一样,都是用于检测数据类型,isRef是检测是不是一个ref对象,跟isReactive函数实现起来一样,我们先来写一个单元测试
这里要实现的功能是,检测ref对象肯定就通过返回true,检测普通类型数据以及reactive对象都是false
it("it should return a boolean", () => { let obj = ref(1) let a = 1 let b = reactive({ user: 1 }) expect(isRef(obj)).toBe(true) expect(isRef(a)).toBe(false) expect(isRef(b)).toBe(false) })
我们在ref.ts中把逻辑写好,首先肯定要返回一个isRef的函数对象,接着我们读取某个属性,如果是ref,那么可以读到,如果不是ref那么它没有这个属性,就会为false
class RefImpl { private _value private _raw public dep //是否是ref的标识 public __v_isRef = true constructor(value) { //保存没有代理前的value this._raw = value //做对象类型检测 this._value = isObject(value) ? reactive(value) : value this.dep = new Set() } get value() { trackRefValue(this.dep) return this._value } set value(newValue) { if (!isHasChanged(this._raw, newValue)) return this._raw = newValue this._value = newValue tiggerEffect(this.dep) } }
我们用一个__v_isRef来标识ref,当我们能读到这个属性是那么肯定就是ref对象了
export function isRef(value) { return !!value.__v_isRef }
为什么要用!!转义呢,因为当我们传入的数据比如是1 a {name: 1}这种不是响应式对象 以及reactive对象,他们身上就没有__v_isRef属性,返回值是undefined,因此用!!转义一下,变成布尔值
unRef
在 Vue 3 中,unRef用于获取一个可能是响应式对象或 ref 对象的原始值,以避免对响应式对象的重复包装或 ref 对象的.value访问, 如果不是一个ref对象的话也返回它的值,先来看一下单测
it("it should return a value", () => { let obj = ref(2) let a = 1 expect(unRef(obj)).toBe(2) expect(unRef(a)).toBe(1) })
我们想一下思路。当我们传入的是ref对象时,我们返回.value即可,若不是ref对象那好办,直接返回它的值
我们来实现一下, 我们只用检测一下是不是ref即可,上面的isRef刚好可以检验
export function unRef(ref) { return isRef(ref) ? ref.value : ref }
这样代码就已经都实现啦,是不是很容易了,我们在写源码的过程中一定要理清楚逻辑关系