1. reactive
-
createReactiveObject
-
该方法传入五个参数,分别为:
-
target: Target
- 意义 :这是要被转换成响应式对象的原始对象。在 Vue 的响应式系统中,任何可以被
Proxy
包装的 JavaScript 对象或集合都可以作为target
。 - 用途:这个参数是响应式转换的直接目标,函数将基于这个目标对象创建一个响应式代理。
- 意义 :这是要被转换成响应式对象的原始对象。在 Vue 的响应式系统中,任何可以被
-
isReadonly: boolean
- 意义:这个布尔值指示创建的响应式对象是否应该是只读的。
- 用途 :如果设置为
true
,则代理将拦截所有尝试修改目标对象的操作,并可能抛出警告或错误,阻止这些修改。
-
baseHandlers: ProxyHandler<any>
- 意义 :这是一个包含各种拦截函数(如
get
,set
,deleteProperty
等)的对象,用于普通对象的响应式处理。 - 用途:这些处理器定义了对普通对象进行操作时的行为,例如如何追踪依赖、触发更新等。
- 意义 :这是一个包含各种拦截函数(如
-
collectionHandlers: ProxyHandler<any>
- 意义 :这是一个专为处理 JavaScript 的集合类型(如
Map
,Set
,WeakMap
,WeakSet
等)设计的拦截处理器集。 - 用途:集合类型由于其内部结构和使用方式的特殊性,需要不同的拦截逻辑来实现响应式功能
- 意义 :这是一个专为处理 JavaScript 的集合类型(如
-
proxyMap: WeakMap<Target, any>
- 意义 :这是一个
WeakMap
,用于存储原始目标对象与其代理对象之间的映射。 - 用途 :通过这个映射,Vue 能够为同一个目标对象重复使用同一个代理,避免创建多个代理导致的内存泄漏和性能问题。同时,
WeakMap
的使用确保了当原始对象不再被引用时,其代理对象也可以被垃圾回收,从而优化了内存使用。
- 意义 :这是一个
-
进入该函数:
typescript//判断传入的东西是否为对象,只有对象类型才可以,如果不是对象直接返回,如果是在开发环境中返回警告 if (!isObject(target)) { if (__DEV__) { warn(`value cannot be made reactive: ${String(target)}`) } return target } //这里的isObject export const isObject = (val: unknown): val is Record<any, any> => val !== null && typeof val === 'object'
-
继续进行检查
kotlin// 如果对象已经是一个Proxy,返回 // exception: calling readonly() on a reactive object if ( target[ReactiveFlags.RAW] && !(isReadonly && target[ReactiveFlags.IS_REACTIVE]) ) { return target } //target[ReactiveFlags.RAW]:这个条件检查 target 对象是否具有 ReactiveFlags.RAW 标志。在 Vue 3 中,ReactiveFlags.RAW 标志用于存储原始对象的引用,通常在对象被转换成响应式对象时设置。如果该属性存在,说明 target 已经是一个通过 reactive 或类似方法处理过的响应式代理,其 RAW 属性指向未被代理的原始对象。 //isReadonly && target[ReactiveFlags.IS_REACTIVE]:这里检查两个条件:isReadonly 是否为真,以及 target 是否具有 ReactiveFlags.IS_REACTIVE 标志。isReadonly 表明当前的操作是试图创建一个只读响应式对象,而 ReactiveFlags.IS_REACTIVE 检查 target 是否已经是一个响应式对象。 //该代码本质上还是优化Vue的性能
-
继续
kotlin// target already has corresponding Proxy const existingProxy = proxyMap.get(target) if (existingProxy) { return existingProxy } //这段代码中的proxyMap指的是Vue中已经创建和缓存的对象 //在Vue中使用的是weakMap这种对象,这种对象可以使Obj作为key,而且垃圾收集器会自动回收这个指代的对象 //换句话说,如果没有其他引用指向这个键对象,它会被垃圾回收掉,其对应的值(响应式代理)也会随之消失。
javascript// only specific value types can be observed. //只有特定类型的值可以被监听 const targetType = getTargetType(target) if (targetType === TargetType.INVALID) { return target } //下面是获取目标的类型方法 function getTargetType(value: Target) { return value[ReactiveFlags.SKIP] || !Object.isExtensible(value) ? TargetType.INVALID : targetTypeMap(toRawType(value)) } //value[ReactiveFlags.SKIP] || !Object.isExtensible(value):value[ReactiveFlags.SKIP]:这部分检查目标对象 value 是否具有 ReactiveFlags.SKIP 标志。在 Vue 3 中,如果一个对象的 __v_skip 属性(对应 ReactiveFlags.SKIP)被设置为 true,则该对象不会被转换为响应式对象。这常用于跳过不需要响应式处理的内部对象或第三方库对象。 //!Object.isExtensible(value):这个检查使用 Object.isExtensible() 方法来判断目标对象 value 是否是可扩展的(即能否添加新的属性)。如果一个对象不是可扩展的,那么它也不适合转换成响应式对象,因为响应式系统需要能够添加响应式处理所需的内部属性。 //如果以上一个为真,就直接返回INVALID,不适合转换 //使用了Vue中的一个内置的方法,该方法通通过获取转为String的类型,获取准确的方法 export const toRawType = (value: unknown): string => { // extract "RawType" from strings like "[object RawType]" return toTypeString(value).slice(8, -1) } //再使用targetTypeMap方法 function targetTypeMap(rawType: string) { switch (rawType) { case 'Object': case 'Array': return TargetType.COMMON case 'Map': case 'Set': case 'WeakMap': case 'WeakSet': return TargetType.COLLECTION default: return TargetType.INVALID } } //获取对应的类型0,1,2
csharp//创建代理对象 const proxy = new Proxy( target, targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers, ) //Proxy有两个参数,第一个为代理对象,第二个为当方法变动处理的方法 //这里的第二个参数表示是否为特殊类型collectionHandlers || baseHandlers proxyMap.set(target, proxy) //在weakMap缓存中存入该对象key:value return proxy
-
2.isReactive
Checks if an object is a proxy created by ,检查是否为Proxy创建
scss
export function isReactive(value: unknown): boolean {
if (isReadonly(value)) {
return isReactive((value as Target)[ReactiveFlags.RAW])
}
return !!(value && (value as Target)[ReactiveFlags.IS_REACTIVE])
}
//检查对象,如果是isReadonly,就会去尝试读取源对象eactiveFlags.RAW
//如果为不是只读,读取ReactiveFlags.IS_REACTIVE 标志
//!!返回结果
3.isReadonly,isShallow, isProxy
都是类似的操作,通过读取原始对象中的isXXX来确定是否为对应的类型
4. toRaw
返回Vue创建的代理的原始对象
csharp
export function toRaw<T>(observed: T): T {
const raw = observed && (observed as Target)[ReactiveFlags.RAW]
return raw ? toRaw(raw) : observed
}
//这里的RAW是Vue中的ReactiveFlags中的一个,表示原始对象
//递归解包,获取最底层的数据
5.MarkRaw
该方法会标记对象,使其不会转换为代理,返回对象本身。
typescript
export function markRaw<T extends object>(value: T): Raw<T> {
//检查对象是否可拓展,只有可拓展的函数才可以修改
if (Object.isExtensible(value)) {
def(value, ReactiveFlags.SKIP, true)
}
return value
}
//该方法会标记对象,如果该对象式可继承的,通过def函数,修改函数的对象
export const def = (obj: object, key: string | symbol, value: any) => {
Object.defineProperty(obj, key, {
configurable: true,
enumerable: false,
value,
})
}
//给该函数标记跳过
//主要用于第三方库和内部系统简化处理
6.toReactive
typescript
export const toReactive = <T extends unknown>(value: T): T =>
//判断是否为对象,如果是直接进行toReactive处理,如果不是直接返回原始数据
isObject(value) ? reactive(value) : value
// return createReactiveObject(
// target,
// false,
// mutableHandlers,
// mutableCollectionHandlers,
// reactiveMap,
//)
7.toReadonly
返回一个只读的proxy对象,同样调用toReactive处理,但是传入参数不同
typescript
export const toReadonly = <T extends unknown>(value: T): DeepReadonly<T> =>
isObject(value) ? readonly(value) : (value as DeepReadonly<T>)
//return createReactiveObject(
// target,
// true,
// readonlyHandlers,
// readonlyCollectionHandlers,
// readonlyMap,
//)