VUE 3.0源码之reactive

本文详细介绍了Vue 3.0中reactive的实现过程,从常规调用流程出发,深入到createReactiveObject的判断与Proxy的使用,特别是mutableHandlers中的get和set方法,如何实现依赖收集、子属性代理以及性能优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

常规调用流程

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)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值