Vue3 使用了新的方式进行响应式处理ES6 Proxy对象,并且也对ES6新增的数据类型:数组集合,也进行响应处理(Vue2没有对数组集合进行响应式处理)
reactive api 的源代码地址在 vue-next3.2\packages\reactivity\src\reactive.ts
export function reactive(target: object) {
// 如果目标对象已经是只读代理 返回只读代理对象
if (target && (target as Target)[ReactiveFlags.IS_READONLY]) {
return target
}
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers,
reactiveMap
)
}
为了对其他创建响应式对象API(shallowReactive readonly shallowReadonly)同时进行处理 有一个创建响应式对象函数 createReactiveObject 进行统一创建,该方法接受5个参数
target响应式处理的目标对象isReadonly是否为只读baseHandler对普通数据(除ES6新增的数组集合) 拦截处理方法collectionHandler对ES6新增的数组集合拦截处理方法proxyMap存储对应响应对象 为了后面可以防止重复调用
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>,
proxyMap: WeakMap<Target, any>
) {
// reactive不会对基础数据类型进行响应式处理
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
}
/*
获取目标对象的数据类型 (如果是 new Number() 等使用构造函数方式创建的数据和变量在前面判断也会是对象,但是如果使用Object原型上的toString去判断就不是对象,而是普通类型值,如:number、string等)
可能是数组集合 或者是 object array 等对象 使用不同的拦截处理方法
*/
// TargetType.INVALID 无效对象 直接返回
const targetType = getTargetType(target)
if (targetType === TargetType.INVALID) {
return target
}
// TargetType.COLLECTION 数组集合标识
const proxy = new Proxy(
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
// 存储响应式对象后返回相应是对象
proxyMap.set(target, proxy)
return proxy
}
相对Vue2, Vue3 不需要一次性从头将目标对象进行响应式处理 会先对象最外层对象进行响应式处理 使用懒加载 当用户获取对象中某个值 会对该值进行响应式处理在返回 并且也对ES6新增的数组集合进行单独处理
最后,以上是我个人理解 如果有没有说到的地方 请各位大佬补充