Vue3.2 响应式原理解析(一)

1,149 阅读2分钟

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新增的数组集合进行单独处理

最后,以上是我个人理解 如果有没有说到的地方 请各位大佬补充