共计 2561 个字符,预计需要花费 7 分钟才能阅读完成。
【vue3 源码】十、响应式 API 中的工具函数
参考代码版本:vue 3.2.37
官网文档:https://vuejs.org/
isRef
export function isRef(r: any): r is Ref {return !!(r && r.__v_isRef === true)
}
通过对象中是否存在 __v_isRef
属性并且 __v_isRef
对应值为 true
来判断是否为ref
。
unref
export function unref<T>(ref: T | Ref<T>): T {return isRef(ref) ? (ref.value as any) : ref
}
如果是 ref
则返回ref.value
,否则间接返回ref
toRef
export function toRef<T extends object, K extends keyof T>(
object: T,
key: K,
defaultValue?: T[K]
): ToRef<T[K]> {const val = object[key]
return isRef(val)
? val
: (new ObjectRefImpl(object, key, defaultValue) as any)
}
toRef
接管三个参数:object
待转换的对象、key
待转换的 key
、defaultValue
默认值。
如果 object[key]
是ref
,则间接返回 object[key]
。否则返回一个ObjectRefImpl
实例。
class ObjectRefImpl<T extends object, K extends keyof T> {
public readonly __v_isRef = true
constructor(
private readonly _object: T,
private readonly _key: K,
private readonly _defaultValue?: T[K]
) {}
get value() {const val = this._object[this._key]
return val === undefined ? (this._defaultValue as T[K]) : val
}
set value(newVal) {this._object[this._key] = newVal
}
}
在 ObjectRefImpl
结构器中会别离将 object
、key
、defaultValue
保留至本人的公有属性中,当获取 ObjectRefImpl
实例的 value
属性时,会从 this._object
中获取数据,因为 this._object
和原来的 object
内存地址是统一的,所以这和间接应用 object
获取 key
获取数据没有区别,只不过通过 toRef
转换之后,能够和 ref
那样,通过 value
属性进行取值、设值。
toRefs
export function toRefs<T extends object>(object: T): ToRefs<T> {if (__DEV__ && !isProxy(object)) {console.warn(`toRefs() expects a reactive object but received a plain one.`)
}
const ret: any = isArray(object) ? new Array(object.length) : {}
for (const key in object) {ret[key] = toRef(object, key)
}
return ret
}
toRefs
中会申明一个新的对象或数组,而后遍历 object
的key
值,并调用toRef
,将后果存入新的对象或数组中,最初返回这个新的对象或数组。
isReactive
export function isReactive(value: unknown): boolean {if (isReadonly(value)) {return isReactive((value as Target)[ReactiveFlags.RAW])
}
return !!(value && (value as Target)[ReactiveFlags.IS_REACTIVE])
}
如果 value
是只读的,那么就对 value
的ReactiveFlags.RAW
属性持续调用 isReactive
;否则依据value
的ReactiveFlags.IS_REACTIVE
属性判断是否为reactive
。
isReadonly
export function isReadonly(value: unknown): boolean {return !!(value && (value as Target)[ReactiveFlags.IS_READONLY])
}
通过 value
的ReactiveFlags.IS_READONLY
属性判断是否只读。
isProxy
isProxy
是用来判断 value
是否为 reactive
或readonly
,并不是用来判断 value
是proxy
类型的
export function isProxy(value: unknown): boolean {return isReactive(value) || isReadonly(value)
}
toRaw
获取传入对象的原始对象。
export function toRaw<T>(observed: T): T {const raw = observed && (observed as Target)[ReactiveFlags.RAW]
return raw ? toRaw(raw) : observed
}
observed
的 ReactiveFlags.RAW
属性能够返回对象的原始对象,但这个原始对象有可能也是能够响应式对象(如readonly(reactive(obj))
),所以递归调用toRaw
,以获取真正的原始对象。
markRaw
将对象标记为永远不能转为 reactive
对象。
export function markRaw<T extends object>(value: T): T & {[RawSymbol]?: true } {def(value, ReactiveFlags.SKIP, true)
return value
}
通过 Object.defineProperty
将value
的 ReactiveFlags.SKIP
(不会被遍历)属性标记为true
。当尝试创立reactive
时,会查看该值。