常规调用流程
1. reactive
这里会先做一个简单的判断,如果通过则调用createReactiveObject
function reactive(target: object) {
// 如果只读,则直接返回target
if (target && (target as Target).__v_isReadonly) {
return target
}
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers
)
}
2. createReactiveObject
这里会做一些可行性和是否代理过的判断,都通过后会调用new Proxy实现代理,具体实现在mutableHandlers
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>
) {
if (!isObject(target)) {
if (__DEV__) {
console.warn(`value cannot be made reactive: ${String(target)}`)
}
return target
}
// 如果已代理则直接返回,除非是只读的
if (target.__v_raw && !(isReadonly && target.__v_isReactive)) {
return target
}
// 判断是否有相应代理,如果有则直接返回代理
if (
hasOwn(target, isReadonly ? ReactiveFlags.readonly : ReactiveFlags.reactive)
) {
return isReadonly ? target.__v_readonly : target.__v_reactive
}
// 判断是否可代理
if (!canObserve(target)) {
return target
}
// 使用Proxy代理
const observed = new Proxy(
target,
// 判断是否为Set,Map,WeakSet,WeakMap
collectionTypes.has(target.constructor) ? collectionHandlers : baseHandlers
)
// 通过Object.defineProperty给target添加第二个参数为key,第三个参数为值
def(
target,
isReadonly ? ReactiveFlags.readonly : ReactiveFlags.reactive,
observed
)
return observed
}
3. mutableHandlers
这里创建一个代理的对象,包括:get、set、deleteProperty、has、ownKeys
- get(createGetter)
调用get会收集依赖,并对子属性中的object类型进行代理,这种方式可以节省初始化时性能和内存
function createGetter(isReadonly = false, shallow = false) {
return function get(target: object, key: string | symbol, receiver: object) {
// 对内部属性直接返回
if (key === ReactiveFlags.isReactive) {
return !isReadonly
} else if (key === ReactiveFlags.isReadonly) {
return isReadonly
} else if (key === ReactiveFlags.raw) {
return target
}
const targetIsArray = isArray(target)
// 对于数组,当调用'includes', 'indexOf', 'lastIndexOf'这几个方法则直接调用
if (targetIsArray && hasOwn(arrayInstrumentations, key)) {
return Reflect.get(arrayInstrumentations, key, receiver)
}
// 获取值
const res = Reflect.get(target, key, receiver)
// 如果内部的Symbol值或读取原型链则直接返回值
if ((isSymbol(key) && builtInSymbols.has(key)) || key === '__proto__') {
return res
}
// 如果浅代理且非只读则直接收集依赖
if (shallow) {
!isReadonly && track(target, TrackOpTypes.GET, key)
return res
}
if (isRef(res)) {
if (targetIsArray) {
!isReadonly && track(target, TrackOpTypes.GET, key)
return res
} else {
// ref unwrapping, only for Objects, not for Arrays.
return res.value
}
}
// 不是只读则收集依赖
!isReadonly && track(target, TrackOpTypes.GET, key)
// 如果值是数组或对象则对值继续做代理
return isObject(res)
? isReadonly
? // need to lazy access readonly and reactive here to avoid
// circular dependency
readonly(res)
: reactive(res)
: res
}
}
- set(createSetter)
赋值并触发相关deps
function createSetter(isReadonly = false, shallow = false) {
return function set(
target: object,
key: string | symbol,
value: unknown,
receiver: object
): boolean {
// 如果是Ref则直接赋值并结束
const oldValue = (target as any)[key]
if (!shallow) {
// 根据value取value的原始值
value = toRaw(value)
if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
oldValue.value = value
return true
}
} else {
// in shallow mode, objects are set as-is regardless of reactive or not
}
// 通过Object.hasOwnProperty判断是否有key
const hadKey = hasOwn(target, key)
const result = Reflect.set(target, key, value, receiver)
// 如果target是原始值,则根据key是否存在处理SET和ADD
if (target === toRaw(receiver)) {
if (!hadKey) {
// trigger方法会触发相关的deps
trigger(target, TriggerOpTypes.ADD, key, value)
} else if (hasChanged(value, oldValue)) {
trigger(target, TriggerOpTypes.SET, key, value, oldValue)
}
}
return result
}
}
- deleteProperty
function deleteProperty(target: object, key: string | symbol): boolean {
const hadKey = hasOwn(target, key)
const oldValue = (target as any)[key]
const result = Reflect.deleteProperty(target, key)
if (result && hadKey) {
// 如果target是数组或iterate,则会触发相关deps
trigger(target, TriggerOpTypes.DELETE, key, undefined, oldValue)
}
return result
}
- has
function has(target: object, key: string | symbol): boolean {
const result = Reflect.has(target, key)
// 这里也会初始化并添加deps
track(target, TrackOpTypes.HAS, key)
return result
}
- ownKeys
function ownKeys(target: object): (string | number | symbol)[] {
// 这里类似get会收集依赖,但键值是 const ITERATE_KEY = Symbol(__DEV__ ? 'iterate' : '')
track(target, TrackOpTypes.ITERATE, ITERATE_KEY)
return Reflect.ownKeys(target)
}