reactive
export function reactive(target: object) {
// 判断是否是只读对象,
if (isReadonly(target)) {
return target
}
return createReactiveObject(
target,
false,
mutableHandlers, // 普通对象的 Proxy 的处理函数对象
mutableCollectionHandlers, // 集合对象的 Proxy 的处理函数对象
reactiveMap // 用于缓存代理对象
)
}
reactive 函数的实现,它接收一个对象 target 作为参数,并返回一个响应式的代理对象。
首先,isReadonly(target) 判断是否是只读对象,如果是,则直接返回该对象本身,因为只读对象不需要变成响应式。
如果 target 不是只读对象,则调用 createReactiveObject 函数创建一个响应式代理对象。
mutableHandlers
export const mutableHandlers: ProxyHandler<object> = {
get, // 当读取可变响应式对象的属性值时会调用该函数。
set, // 当设置可变响应式对象的属性值时会调用该函数。
deleteProperty, // 当删除可变响应式对象的属性时会调用该函数。
has, // 当使用 in 或 Reflect.has() 方法检查可变响应式对象是否包含某个属性时会调用该函数。
ownKeys // 当使用 Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()、Object.keys() 或 Reflect.ownKeys() 获取可变响应式对象自身属性时会调用该函数。
}
mutableCollectionHandlers
export const mutableCollectionHandlers: ProxyHandler<CollectionTypes> = {
get: /*#__PURE__*/ createInstrumentationGetter(false, false)
}
mutableCollectionHandlers是一个用于代理集合对象的ProxyHandler,其主要是通过调用createInstrumentationGetter来返回一个getter函数用于拦截集合对象的读取操作,不支持集合对象的写入操作和删除操作。
createInstrumentationGetter是一个工厂函数
createReactiveObject
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>,
proxyMap: WeakMap<Target, any>
) {
if (!isObject(target)) {
if (__DEV__) {
console.warn(`value cannot be made reactive: ${String(target)}`)
}
return target
}
if (
target[ReactiveFlags.RAW] &&
!(isReadonly && target[ReactiveFlags.IS_REACTIVE])
) {
return target
}
const existingProxy = proxyMap.get(target)
if (existingProxy) {
return existingProxy
}
const targetType = getTargetType(target)
if (targetType === TargetType.INVALID) {
return target
}
const proxy = new Proxy(
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
proxyMap.set(target, proxy)
return proxy
}
如果 target 不是一个对象,则直接返回 target,并在控制台发出警告。如果 target 已经是一个响应式代理,则返回原始的响应式代理对象。如果 target 已经被代理过,则直接返回已存在的代理对象。如果 target 不是有效的响应式对象类型,则直接返回 target。否则,就创建一个新的代理对象 proxy,并将 target 和 proxy 存入 proxyMap 中。如果 target 是集合类型的对象,则使用 collectionHandlers,否则使用 baseHandlers 作为代理处理程序。
最后返回 proxy 代理对象。
总结
reactive函数接收一个target对象,返回一个代理proxy对象,实现对象的响应式。
具体过程如下:
- 判断
target是否为基本类型或者null,如果是,直接返回target; - 判断
target是否已经有对应的代理proxy,如果有,直接返回代理对象; - 判断
target的类型是否能够被观测,如果不能,直接返回target; - 如果
target是一个已经被代理的对象,返回它的代理对象; - 创建一个新的代理
proxy对象,如果target是一个集合对象(如Map、Set等),使用collectionHandlers,否则使用baseHandlers; - 将
target和proxy存入proxyMap,以备后续使用; - 返回
proxy对象。
这个代理对象会重写target的访问,实现属性访问和属性修改的拦截。当我们访问proxy对象时,get函数会被调用,此时会触发依赖收集,收集当前属性的依赖关系,以便在属性修改时通知相关的响应式更新。而当我们修改proxy对象的属性时,set函数会被调用,此时会触发依赖更新,通知相关的响应式进行更新。