乐趣区

关于前端:vue3源码十响应式API中的工具函数

【vue3 源码】十、响应式 API 中的工具函数

参考代码版本:vue 3.2.37

官网文档:https://vuejs.org/

isRef

export function isRef(r: any): r is Ref {return !!(r && r.__v_isRef === true)
}

通过对象中是否存在 __v_isRef 属性并且 __v_isRef 对应值为 true 来判断是否为ref

unref

export function unref<T>(ref: T | Ref<T>): T {return isRef(ref) ? (ref.value as any) : ref
}

如果是 ref 则返回ref.value,否则间接返回ref

toRef

export function toRef<T extends object, K extends keyof T>(
  object: T,
  key: K,
  defaultValue?: T[K]
): ToRef<T[K]> {const val = object[key]
  return isRef(val)
    ? val
    : (new ObjectRefImpl(object, key, defaultValue) as any)
}

toRef接管三个参数:object待转换的对象、key待转换的 keydefaultValue 默认值。

如果 object[key]ref,则间接返回 object[key]。否则返回一个ObjectRefImpl 实例。

class ObjectRefImpl<T extends object, K extends keyof T> {
  public readonly __v_isRef = true

  constructor(
    private readonly _object: T,
    private readonly _key: K,
    private readonly _defaultValue?: T[K]
  ) {}

  get value() {const val = this._object[this._key]
    return val === undefined ? (this._defaultValue as T[K]) : val
  }

  set value(newVal) {this._object[this._key] = newVal
  }
}

ObjectRefImpl 结构器中会别离将 objectkeydefaultValue 保留至本人的公有属性中,当获取 ObjectRefImpl 实例的 value 属性时,会从 this._object 中获取数据,因为 this._object 和原来的 object 内存地址是统一的,所以这和间接应用 object 获取 key 获取数据没有区别,只不过通过 toRef 转换之后,能够和 ref 那样,通过 value 属性进行取值、设值。

toRefs

export function toRefs<T extends object>(object: T): ToRefs<T> {if (__DEV__ && !isProxy(object)) {console.warn(`toRefs() expects a reactive object but received a plain one.`)
  }
  const ret: any = isArray(object) ? new Array(object.length) : {}
  for (const key in object) {ret[key] = toRef(object, key)
  }
  return ret
}

toRefs中会申明一个新的对象或数组,而后遍历 objectkey值,并调用toRef,将后果存入新的对象或数组中,最初返回这个新的对象或数组。

isReactive

export function isReactive(value: unknown): boolean {if (isReadonly(value)) {return isReactive((value as Target)[ReactiveFlags.RAW])
  }
  return !!(value && (value as Target)[ReactiveFlags.IS_REACTIVE])
}

如果 value 是只读的,那么就对 valueReactiveFlags.RAW属性持续调用 isReactive;否则依据valueReactiveFlags.IS_REACTIVE属性判断是否为reactive

isReadonly

export function isReadonly(value: unknown): boolean {return !!(value && (value as Target)[ReactiveFlags.IS_READONLY])
}

通过 valueReactiveFlags.IS_READONLY属性判断是否只读。

isProxy

isProxy是用来判断 value 是否为 reactivereadonly,并不是用来判断 valueproxy类型的

export function isProxy(value: unknown): boolean {return isReactive(value) || isReadonly(value)
}

toRaw

获取传入对象的原始对象。

export function toRaw<T>(observed: T): T {const raw = observed && (observed as Target)[ReactiveFlags.RAW]
  return raw ? toRaw(raw) : observed
}

observedReactiveFlags.RAW 属性能够返回对象的原始对象,但这个原始对象有可能也是能够响应式对象(如readonly(reactive(obj))),所以递归调用toRaw,以获取真正的原始对象。

markRaw

将对象标记为永远不能转为 reactive 对象。

export function markRaw<T extends object>(value: T): T & {[RawSymbol]?: true } {def(value, ReactiveFlags.SKIP, true)
  return value
}

通过 Object.definePropertyvalueReactiveFlags.SKIP(不会被遍历)属性标记为true。当尝试创立reactive 时,会查看该值。

退出移动版